commune-ai 0.2.2 → 0.2.4

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
@@ -263,6 +263,95 @@ export COMMUNE_API_KEY="your_key_from_dashboard"
263
263
 
264
264
  ---
265
265
 
266
+ ## Structured extraction (per inbox)
267
+ You can attach a **JSON schema** to a specific inbox so Commune extracts structured data from inbound emails.
268
+
269
+ ### 1) Add a schema to an inbox (dashboard)
270
+ In **Dashboard → Inboxes**, open an inbox and add a Structured Extraction schema. Save it and enable extraction.
271
+
272
+ ### 2) Set the schema via SDK (optional)
273
+ ```ts
274
+ await client.inboxes.setExtractionSchema({
275
+ domainId: "domain-123",
276
+ inboxId: "inbox-456",
277
+ schema: {
278
+ name: "invoice_extraction",
279
+ description: "Extract invoice details",
280
+ enabled: true,
281
+ schema: {
282
+ type: "object",
283
+ properties: {
284
+ invoiceNumber: { type: "string" },
285
+ amount: { type: "number" },
286
+ dueDate: { type: "string" }
287
+ },
288
+ required: ["invoiceNumber", "amount"],
289
+ additionalProperties: false
290
+ }
291
+ }
292
+ });
293
+ ```
294
+
295
+ ### 3) Read extracted data in your webhook
296
+ The webhook payload includes the structured output when extraction is enabled.
297
+
298
+ ```ts
299
+ const handler = createWebhookHandler({
300
+ onEvent: async (message, context) => {
301
+ const extracted = context.payload.extractedData
302
+ || message.metadata?.extracted_data
303
+ || null;
304
+
305
+ if (extracted) {
306
+ // use structured fields in your agent workflow
307
+ console.log("Extracted:", extracted);
308
+ }
309
+ },
310
+ });
311
+ ```
312
+
313
+ > Tip: Keep your schema minimal (only the fields you need). You can evolve it over time.
314
+
315
+ ### Example: Invoice extraction (end-to-end)
316
+ ```ts
317
+ import { CommuneClient, createWebhookHandler } from "@commune/sdk";
318
+
319
+ const client = new CommuneClient({ apiKey: process.env.COMMUNE_API_KEY! });
320
+
321
+ await client.inboxes.setExtractionSchema({
322
+ domainId: "domain-123",
323
+ inboxId: "inbox-456",
324
+ schema: {
325
+ name: "invoice_extraction",
326
+ enabled: true,
327
+ schema: {
328
+ type: "object",
329
+ properties: {
330
+ invoiceNumber: { type: "string" },
331
+ amount: { type: "number" },
332
+ vendor: { type: "string" }
333
+ },
334
+ required: ["invoiceNumber", "amount"],
335
+ additionalProperties: false
336
+ }
337
+ }
338
+ });
339
+
340
+ const handler = createWebhookHandler({
341
+ onEvent: async (message, context) => {
342
+ const extracted = context.payload.extractedData;
343
+ if (!extracted) return;
344
+
345
+ console.log("Invoice:", extracted.invoiceNumber);
346
+ console.log("Amount:", extracted.amount);
347
+
348
+ await processInvoice(extracted);
349
+ },
350
+ });
351
+ ```
352
+
353
+ ---
354
+
266
355
  ## Webhook verification (Commune → your app)
267
356
  Commune signs outbound webhooks using your **inbox webhook secret**. Verify the
268
357
  signature before processing the request.
package/dist/client.d.ts CHANGED
@@ -19,11 +19,6 @@ export declare class CommuneClient {
19
19
  verify: (domainId: string) => Promise<Record<string, unknown>>;
20
20
  records: (domainId: string) => Promise<unknown[]>;
21
21
  status: (domainId: string) => Promise<Record<string, unknown>>;
22
- createWebhook: (domainId: string, payload?: {
23
- endpoint?: string;
24
- events?: string[];
25
- }) => Promise<Record<string, unknown>>;
26
- saveWebhookSecret: (domainId: string, secret: string) => Promise<Record<string, unknown>>;
27
22
  };
28
23
  inboxes: {
29
24
  list: (domainId: string) => Promise<InboxEntry[]>;
@@ -46,6 +41,20 @@ export declare class CommuneClient {
46
41
  endpoint: string;
47
42
  events?: string[];
48
43
  }) => Promise<InboxEntry>;
44
+ setExtractionSchema: (payload: {
45
+ domainId: string;
46
+ inboxId: string;
47
+ schema: {
48
+ name: string;
49
+ description?: string;
50
+ enabled?: boolean;
51
+ schema: Record<string, any>;
52
+ };
53
+ }) => Promise<InboxEntry>;
54
+ removeExtractionSchema: (payload: {
55
+ domainId: string;
56
+ inboxId: string;
57
+ }) => Promise<InboxEntry>;
49
58
  };
50
59
  messages: {
51
60
  send: (payload: SendMessagePayload) => Promise<Record<string, unknown>>;
package/dist/client.js CHANGED
@@ -38,15 +38,6 @@ export class CommuneClient {
38
38
  status: async (domainId) => {
39
39
  return this.request(`/api/domains/${encodeURIComponent(domainId)}/status`);
40
40
  },
41
- createWebhook: async (domainId, payload) => {
42
- return this.request(`/api/domains/${encodeURIComponent(domainId)}/webhook`, {
43
- method: 'POST',
44
- json: payload,
45
- });
46
- },
47
- saveWebhookSecret: async (domainId, secret) => {
48
- return this.request(`/api/domains/${encodeURIComponent(domainId)}/webhook/secret`, { method: 'POST', json: { secret } });
49
- },
50
41
  };
51
42
  this.inboxes = {
52
43
  list: async (domainId) => {
@@ -70,14 +61,20 @@ export class CommuneClient {
70
61
  setWebhook: async (domainId, inboxId, payload) => {
71
62
  return this.request(`/api/domains/${encodeURIComponent(domainId)}/inboxes/${encodeURIComponent(inboxId)}/webhook`, { method: 'POST', json: payload });
72
63
  },
64
+ setExtractionSchema: async (payload) => {
65
+ const { domainId, inboxId, schema } = payload;
66
+ return this.request(`/api/domains/${encodeURIComponent(domainId)}/inboxes/${encodeURIComponent(inboxId)}/extraction-schema`, { method: 'PUT', json: schema });
67
+ },
68
+ removeExtractionSchema: async (payload) => {
69
+ const { domainId, inboxId } = payload;
70
+ return this.request(`/api/domains/${encodeURIComponent(domainId)}/inboxes/${encodeURIComponent(inboxId)}/extraction-schema`, { method: 'DELETE' });
71
+ },
73
72
  };
74
73
  this.messages = {
75
74
  send: async (payload) => {
76
- // Always send as email (Slack support coming soon)
77
- const emailPayload = { ...payload, channel: 'email' };
78
75
  return this.request('/api/messages/send', {
79
76
  method: 'POST',
80
- json: emailPayload,
77
+ json: payload,
81
78
  });
82
79
  },
83
80
  list: async (params) => {
@@ -99,10 +96,8 @@ export class CommuneClient {
99
96
  })}`);
100
97
  },
101
98
  };
102
- // Semantic search across all organizational emails (coming soon)
99
+ // Semantic search across all organizational emails
103
100
  this.search = async (params) => {
104
- // Placeholder for future semantic search implementation
105
- // This will search across all emails in the organization
106
101
  return this.request(`/api/search${buildQuery({
107
102
  q: params.query,
108
103
  limit: params.limit || 10,
@@ -117,16 +112,10 @@ export class CommuneClient {
117
112
  return this.request(`/api/attachments/${encodeURIComponent(attachmentId)}`);
118
113
  },
119
114
  };
120
- if (!options.apiKey) {
121
- throw new Error('API key is required. Get one from your Commune dashboard at https://commune.ai');
122
- }
123
115
  this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, '');
124
116
  this.apiKey = options.apiKey;
125
117
  this.headers = options.headers;
126
118
  this.fetcher = options.fetcher || fetch;
127
- if (!this.apiKey) {
128
- throw new Error('CommuneClient requires apiKey');
129
- }
130
119
  }
131
120
  async request(path, options = {}) {
132
121
  const { json, headers, ...rest } = options;
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { CommuneClient } from './client.js';
2
- export { verifyResendWebhook, verifySlackWebhook, verifyCommuneWebhook } from './webhooks.js';
2
+ export { verifyResendWebhook } from './webhooks.js';
3
3
  export { createWebhookHandler } from './listener.js';
package/dist/types.d.ts CHANGED
@@ -17,6 +17,7 @@ export interface MessageMetadata {
17
17
  message_id?: string | null;
18
18
  provider?: 'resend' | 'email' | string;
19
19
  raw?: unknown;
20
+ extracted_data?: Record<string, any>;
20
21
  }
21
22
  export interface UnifiedMessage {
22
23
  _id?: string;
@@ -63,6 +64,12 @@ export interface InboxEntry {
63
64
  metadata?: Record<string, unknown>;
64
65
  };
65
66
  webhook?: InboxWebhook;
67
+ extractionSchema?: {
68
+ name: string;
69
+ description?: string;
70
+ schema: Record<string, any>;
71
+ enabled: boolean;
72
+ };
66
73
  createdAt?: string;
67
74
  status?: string;
68
75
  }
@@ -132,6 +139,7 @@ export interface InboundEmailWebhookPayload {
132
139
  event: unknown;
133
140
  email: unknown;
134
141
  message: UnifiedMessage;
142
+ extractedData?: Record<string, any>;
135
143
  }
136
144
  export interface ApiError {
137
145
  message?: string;
package/dist/webhooks.js CHANGED
@@ -1,4 +1,3 @@
1
- import crypto from 'crypto';
2
1
  import { Webhook } from 'svix';
3
2
  export const verifyResendWebhook = (payload, headers, secret) => {
4
3
  const webhook = new Webhook(secret);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commune-ai",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Our email infrastructure - webhooks, threads, history, and semantic search",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,9 +15,30 @@
15
15
  "dist",
16
16
  "README.md"
17
17
  ],
18
+ "keywords": [
19
+ "email",
20
+ "slack",
21
+ "ai",
22
+ "agent",
23
+ "webhook",
24
+ "communication",
25
+ "inbox",
26
+ "api"
27
+ ],
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/commune-ai/commune"
32
+ },
33
+ "homepage": "https://github.com/commune-ai/commune#readme",
34
+ "bugs": {
35
+ "url": "https://github.com/commune-ai/commune/issues"
36
+ },
18
37
  "scripts": {
19
38
  "build": "tsc -p tsconfig.json",
20
- "clean": "rm -rf dist"
39
+ "clean": "rm -rf dist",
40
+ "prepublishOnly": "npm run clean && npm run build",
41
+ "prepack": "npm run build"
21
42
  },
22
43
  "dependencies": {
23
44
  "svix": "^1.44.0"