@ebowwa/crm 0.1.0

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.
Files changed (187) hide show
  1. package/README.md +174 -0
  2. package/dist/cli/commands/activities.d.ts +11 -0
  3. package/dist/cli/commands/activities.d.ts.map +1 -0
  4. package/dist/cli/commands/activities.js +427 -0
  5. package/dist/cli/commands/activities.js.map +1 -0
  6. package/dist/cli/commands/contacts.d.ts +11 -0
  7. package/dist/cli/commands/contacts.d.ts.map +1 -0
  8. package/dist/cli/commands/contacts.js +458 -0
  9. package/dist/cli/commands/contacts.js.map +1 -0
  10. package/dist/cli/commands/deals.d.ts +11 -0
  11. package/dist/cli/commands/deals.d.ts.map +1 -0
  12. package/dist/cli/commands/deals.js +498 -0
  13. package/dist/cli/commands/deals.js.map +1 -0
  14. package/dist/cli/commands/media.d.ts +11 -0
  15. package/dist/cli/commands/media.d.ts.map +1 -0
  16. package/dist/cli/commands/media.js +417 -0
  17. package/dist/cli/commands/media.js.map +1 -0
  18. package/dist/cli/commands/search.d.ts +11 -0
  19. package/dist/cli/commands/search.d.ts.map +1 -0
  20. package/dist/cli/commands/search.js +346 -0
  21. package/dist/cli/commands/search.js.map +1 -0
  22. package/dist/cli/index.d.ts +13 -0
  23. package/dist/cli/index.d.ts.map +1 -0
  24. package/dist/cli/index.js +173 -0
  25. package/dist/cli/index.js.map +1 -0
  26. package/dist/cli/repl.d.ts +15 -0
  27. package/dist/cli/repl.d.ts.map +1 -0
  28. package/dist/cli/repl.js +318 -0
  29. package/dist/cli/repl.js.map +1 -0
  30. package/dist/cli/utils/config.d.ts +91 -0
  31. package/dist/cli/utils/config.d.ts.map +1 -0
  32. package/dist/cli/utils/config.js +212 -0
  33. package/dist/cli/utils/config.js.map +1 -0
  34. package/dist/cli/utils/output.d.ts +136 -0
  35. package/dist/cli/utils/output.d.ts.map +1 -0
  36. package/dist/cli/utils/output.js +323 -0
  37. package/dist/cli/utils/output.js.map +1 -0
  38. package/dist/cli/utils/prompt.d.ts +81 -0
  39. package/dist/cli/utils/prompt.d.ts.map +1 -0
  40. package/dist/cli/utils/prompt.js +341 -0
  41. package/dist/cli/utils/prompt.js.map +1 -0
  42. package/dist/cli.d.ts +3 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +8 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/core/index.d.ts +6 -0
  47. package/dist/core/index.d.ts.map +1 -0
  48. package/dist/core/index.js +32 -0
  49. package/dist/core/index.js.map +1 -0
  50. package/dist/core/schemas.d.ts +3050 -0
  51. package/dist/core/schemas.d.ts.map +1 -0
  52. package/dist/core/schemas.js +667 -0
  53. package/dist/core/schemas.js.map +1 -0
  54. package/dist/core/types.d.ts +597 -0
  55. package/dist/core/types.d.ts.map +1 -0
  56. package/dist/core/types.js +8 -0
  57. package/dist/core/types.js.map +1 -0
  58. package/dist/index.d.ts +7 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +8 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/mcp/index.d.ts +14 -0
  63. package/dist/mcp/index.d.ts.map +1 -0
  64. package/dist/mcp/index.js +11 -0
  65. package/dist/mcp/index.js.map +1 -0
  66. package/dist/mcp/server.d.ts +13 -0
  67. package/dist/mcp/server.d.ts.map +1 -0
  68. package/dist/mcp/server.js +18 -0
  69. package/dist/mcp/server.js.map +1 -0
  70. package/dist/mcp/storage/client.d.ts +109 -0
  71. package/dist/mcp/storage/client.d.ts.map +1 -0
  72. package/dist/mcp/storage/client.js +355 -0
  73. package/dist/mcp/storage/client.js.map +1 -0
  74. package/dist/mcp/storage/index.d.ts +7 -0
  75. package/dist/mcp/storage/index.d.ts.map +1 -0
  76. package/dist/mcp/storage/index.js +6 -0
  77. package/dist/mcp/storage/index.js.map +1 -0
  78. package/dist/mcp/storage/types.d.ts +44 -0
  79. package/dist/mcp/storage/types.d.ts.map +1 -0
  80. package/dist/mcp/storage/types.js +35 -0
  81. package/dist/mcp/storage/types.js.map +1 -0
  82. package/dist/mcp/tools/definitions.d.ts +16 -0
  83. package/dist/mcp/tools/definitions.d.ts.map +1 -0
  84. package/dist/mcp/tools/definitions.js +914 -0
  85. package/dist/mcp/tools/definitions.js.map +1 -0
  86. package/dist/mcp/tools/handlers.d.ts +50 -0
  87. package/dist/mcp/tools/handlers.d.ts.map +1 -0
  88. package/dist/mcp/tools/handlers.js +760 -0
  89. package/dist/mcp/tools/handlers.js.map +1 -0
  90. package/dist/mcp/tools/index.d.ts +7 -0
  91. package/dist/mcp/tools/index.d.ts.map +1 -0
  92. package/dist/mcp/tools/index.js +6 -0
  93. package/dist/mcp/tools/index.js.map +1 -0
  94. package/dist/mcp/tools/types.d.ts +314 -0
  95. package/dist/mcp/tools/types.d.ts.map +1 -0
  96. package/dist/mcp/tools/types.js +5 -0
  97. package/dist/mcp/tools/types.js.map +1 -0
  98. package/dist/mcp/transports/stdio.d.ts +27 -0
  99. package/dist/mcp/transports/stdio.d.ts.map +1 -0
  100. package/dist/mcp/transports/stdio.js +237 -0
  101. package/dist/mcp/transports/stdio.js.map +1 -0
  102. package/dist/telemetry/index.d.ts +58 -0
  103. package/dist/telemetry/index.d.ts.map +1 -0
  104. package/dist/telemetry/index.js +109 -0
  105. package/dist/telemetry/index.js.map +1 -0
  106. package/dist/telemetry/logger.d.ts +116 -0
  107. package/dist/telemetry/logger.d.ts.map +1 -0
  108. package/dist/telemetry/logger.js +256 -0
  109. package/dist/telemetry/logger.js.map +1 -0
  110. package/dist/telemetry/metrics.d.ts +115 -0
  111. package/dist/telemetry/metrics.d.ts.map +1 -0
  112. package/dist/telemetry/metrics.js +292 -0
  113. package/dist/telemetry/metrics.js.map +1 -0
  114. package/dist/telemetry/tracer.d.ts +227 -0
  115. package/dist/telemetry/tracer.d.ts.map +1 -0
  116. package/dist/telemetry/tracer.js +355 -0
  117. package/dist/telemetry/tracer.js.map +1 -0
  118. package/dist/web/app.d.ts +2 -0
  119. package/dist/web/app.d.ts.map +1 -0
  120. package/dist/web/app.js +115 -0
  121. package/dist/web/app.js.map +1 -0
  122. package/dist/web/components/ContactList.d.ts +3 -0
  123. package/dist/web/components/ContactList.d.ts.map +1 -0
  124. package/dist/web/components/ContactList.js +262 -0
  125. package/dist/web/components/ContactList.js.map +1 -0
  126. package/dist/web/components/Dashboard.d.ts +3 -0
  127. package/dist/web/components/Dashboard.d.ts.map +1 -0
  128. package/dist/web/components/Dashboard.js +158 -0
  129. package/dist/web/components/Dashboard.js.map +1 -0
  130. package/dist/web/components/DealPipeline.d.ts +3 -0
  131. package/dist/web/components/DealPipeline.d.ts.map +1 -0
  132. package/dist/web/components/DealPipeline.js +306 -0
  133. package/dist/web/components/DealPipeline.js.map +1 -0
  134. package/dist/web/index.d.ts +2 -0
  135. package/dist/web/index.d.ts.map +1 -0
  136. package/dist/web/index.js +269 -0
  137. package/dist/web/index.js.map +1 -0
  138. package/dist/web/types.d.ts +75 -0
  139. package/dist/web/types.d.ts.map +1 -0
  140. package/dist/web/types.js +3 -0
  141. package/dist/web/types.js.map +1 -0
  142. package/native/index.d.ts +571 -0
  143. package/native/index.js +687 -0
  144. package/package.json +105 -0
  145. package/src/cli/commands/activities.ts +543 -0
  146. package/src/cli/commands/contacts.ts +563 -0
  147. package/src/cli/commands/deals.ts +637 -0
  148. package/src/cli/commands/media.ts +521 -0
  149. package/src/cli/commands/search.ts +426 -0
  150. package/src/cli/index.ts +203 -0
  151. package/src/cli/repl.ts +379 -0
  152. package/src/cli/utils/config.ts +299 -0
  153. package/src/cli/utils/output.ts +386 -0
  154. package/src/cli/utils/prompt.ts +444 -0
  155. package/src/cli.ts +11 -0
  156. package/src/core/index.ts +184 -0
  157. package/src/core/schemas.ts +770 -0
  158. package/src/core/types.ts +969 -0
  159. package/src/index.ts +8 -0
  160. package/src/mcp/index.ts +17 -0
  161. package/src/mcp/server.ts +26 -0
  162. package/src/mcp/storage/client.ts +408 -0
  163. package/src/mcp/storage/index.ts +7 -0
  164. package/src/mcp/storage/types.ts +72 -0
  165. package/src/mcp/tools/definitions.ts +961 -0
  166. package/src/mcp/tools/handlers.ts +805 -0
  167. package/src/mcp/tools/index.ts +7 -0
  168. package/src/mcp/tools/types.ts +390 -0
  169. package/src/mcp/transports/stdio.ts +225 -0
  170. package/src/telemetry/index.ts +131 -0
  171. package/src/telemetry/logger.ts +318 -0
  172. package/src/telemetry/metrics.ts +393 -0
  173. package/src/telemetry/tracer.ts +487 -0
  174. package/src/web/api/activities.ts +41 -0
  175. package/src/web/api/contacts.ts +114 -0
  176. package/src/web/api/deals.ts +108 -0
  177. package/src/web/api/media.ts +98 -0
  178. package/src/web/app.tsx +143 -0
  179. package/src/web/components/ActivityFeed.tsx +195 -0
  180. package/src/web/components/ContactList.tsx +340 -0
  181. package/src/web/components/Dashboard.tsx +214 -0
  182. package/src/web/components/DealPipeline.tsx +405 -0
  183. package/src/web/components/MediaGallery.tsx +334 -0
  184. package/src/web/index.html +14 -0
  185. package/src/web/index.ts +326 -0
  186. package/src/web/styles/main.css +180 -0
  187. package/src/web/types.ts +311 -0
@@ -0,0 +1,760 @@
1
+ /**
2
+ * MCP Tool handlers for CRM operations
3
+ */
4
+ import { CRMError } from '../storage/types.js';
5
+ /**
6
+ * Tool handlers class containing all MCP tool implementations
7
+ */
8
+ export class ToolHandlers {
9
+ storage;
10
+ constructor(storage) {
11
+ this.storage = storage;
12
+ }
13
+ // ============================================================================
14
+ // Contact Handlers
15
+ // ============================================================================
16
+ async createContact(input) {
17
+ try {
18
+ const name = input.name;
19
+ if (!name) {
20
+ return { success: false, error: 'Contact name is required' };
21
+ }
22
+ const now = new Date().toISOString();
23
+ const contact = await this.storage.insert('contacts', {
24
+ name,
25
+ firstName: input.firstName,
26
+ lastName: input.lastName,
27
+ emails: input.emails ?? [],
28
+ phones: input.phones ?? [],
29
+ addresses: [],
30
+ socialProfiles: [],
31
+ company: input.company,
32
+ title: input.title,
33
+ department: undefined,
34
+ website: undefined,
35
+ tags: input.tags ?? [],
36
+ customFields: [],
37
+ source: input.source,
38
+ status: input.status ?? 'lead',
39
+ ownerId: undefined,
40
+ avatar: undefined,
41
+ preferredContact: undefined,
42
+ language: undefined,
43
+ timezone: undefined,
44
+ preferences: undefined,
45
+ leadScore: undefined,
46
+ doNotContact: false,
47
+ lastContactedAt: undefined,
48
+ nextFollowUpAt: undefined,
49
+ });
50
+ return { success: true, data: contact };
51
+ }
52
+ catch (error) {
53
+ return this.handleError(error);
54
+ }
55
+ }
56
+ async getContact(input) {
57
+ try {
58
+ const id = input.id;
59
+ if (!id) {
60
+ return { success: false, error: 'Contact ID is required' };
61
+ }
62
+ const contact = this.storage.get('contacts', id);
63
+ if (!contact) {
64
+ return { success: false, error: `Contact not found: ${id}` };
65
+ }
66
+ return { success: true, data: contact };
67
+ }
68
+ catch (error) {
69
+ return this.handleError(error);
70
+ }
71
+ }
72
+ async updateContact(input) {
73
+ try {
74
+ const id = input.id;
75
+ if (!id) {
76
+ return { success: false, error: 'Contact ID is required' };
77
+ }
78
+ const updates = {};
79
+ if (input.name !== undefined)
80
+ updates.name = input.name;
81
+ if (input.firstName !== undefined)
82
+ updates.firstName = input.firstName;
83
+ if (input.lastName !== undefined)
84
+ updates.lastName = input.lastName;
85
+ if (input.emails !== undefined)
86
+ updates.emails = input.emails;
87
+ if (input.phones !== undefined)
88
+ updates.phones = input.phones;
89
+ if (input.company !== undefined)
90
+ updates.company = input.company;
91
+ if (input.title !== undefined)
92
+ updates.title = input.title;
93
+ if (input.tags !== undefined)
94
+ updates.tags = input.tags;
95
+ if (input.status !== undefined)
96
+ updates.status = input.status;
97
+ const contact = await this.storage.update('contacts', id, updates);
98
+ return { success: true, data: contact };
99
+ }
100
+ catch (error) {
101
+ return this.handleError(error);
102
+ }
103
+ }
104
+ async deleteContact(input) {
105
+ try {
106
+ const id = input.id;
107
+ if (!id) {
108
+ return { success: false, error: 'Contact ID is required' };
109
+ }
110
+ const deleted = await this.storage.delete('contacts', id);
111
+ return { success: true, data: { id, deleted } };
112
+ }
113
+ catch (error) {
114
+ return this.handleError(error);
115
+ }
116
+ }
117
+ async listContacts(input) {
118
+ try {
119
+ const limit = input.limit ?? 20;
120
+ const offset = input.offset ?? 0;
121
+ const contacts = this.storage.list('contacts', { limit, offset });
122
+ const total = this.storage.count('contacts');
123
+ return { success: true, data: { contacts, total } };
124
+ }
125
+ catch (error) {
126
+ return this.handleError(error);
127
+ }
128
+ }
129
+ async searchContacts(input) {
130
+ try {
131
+ const email = input.email;
132
+ if (!email) {
133
+ return { success: false, error: 'Email is required' };
134
+ }
135
+ const contacts = this.storage.findByIndex('contacts_by_email', email.toLowerCase());
136
+ return { success: true, data: { contacts } };
137
+ }
138
+ catch (error) {
139
+ return this.handleError(error);
140
+ }
141
+ }
142
+ // ============================================================================
143
+ // Deal Handlers
144
+ // ============================================================================
145
+ async createDeal(input) {
146
+ try {
147
+ const title = input.title;
148
+ const contactId = input.contactId;
149
+ const value = input.value;
150
+ const expectedClose = input.expectedClose;
151
+ if (!title)
152
+ return { success: false, error: 'Deal title is required' };
153
+ if (!contactId)
154
+ return { success: false, error: 'Contact ID is required' };
155
+ if (value === undefined)
156
+ return { success: false, error: 'Deal value is required' };
157
+ if (!expectedClose)
158
+ return { success: false, error: 'Expected close date is required' };
159
+ const deal = await this.storage.insert('deals', {
160
+ title,
161
+ contactId,
162
+ companyId: undefined,
163
+ value,
164
+ currency: input.currency ?? 'USD',
165
+ stage: input.stage ?? 'prospecting',
166
+ probability: input.probability ?? 0,
167
+ expectedClose,
168
+ actualClose: undefined,
169
+ priority: input.priority ?? 'medium',
170
+ lineItems: [],
171
+ discount: undefined,
172
+ discountType: undefined,
173
+ totalValue: value,
174
+ notes: input.notes ?? '',
175
+ tags: input.tags ?? [],
176
+ competitors: [],
177
+ lossReason: undefined,
178
+ nextSteps: undefined,
179
+ ownerId: undefined,
180
+ source: undefined,
181
+ customFields: [],
182
+ lastActivityAt: undefined,
183
+ });
184
+ return { success: true, data: deal };
185
+ }
186
+ catch (error) {
187
+ return this.handleError(error);
188
+ }
189
+ }
190
+ async getDeal(input) {
191
+ try {
192
+ const id = input.id;
193
+ if (!id) {
194
+ return { success: false, error: 'Deal ID is required' };
195
+ }
196
+ const deal = this.storage.get('deals', id);
197
+ if (!deal) {
198
+ return { success: false, error: `Deal not found: ${id}` };
199
+ }
200
+ return { success: true, data: deal };
201
+ }
202
+ catch (error) {
203
+ return this.handleError(error);
204
+ }
205
+ }
206
+ async updateDeal(input) {
207
+ try {
208
+ const id = input.id;
209
+ if (!id) {
210
+ return { success: false, error: 'Deal ID is required' };
211
+ }
212
+ const updates = {};
213
+ if (input.title !== undefined)
214
+ updates.title = input.title;
215
+ if (input.value !== undefined)
216
+ updates.value = input.value;
217
+ if (input.stage !== undefined)
218
+ updates.stage = input.stage;
219
+ if (input.probability !== undefined)
220
+ updates.probability = input.probability;
221
+ if (input.expectedClose !== undefined)
222
+ updates.expectedClose = input.expectedClose;
223
+ if (input.actualClose !== undefined)
224
+ updates.actualClose = input.actualClose;
225
+ if (input.priority !== undefined)
226
+ updates.priority = input.priority;
227
+ if (input.notes !== undefined)
228
+ updates.notes = input.notes;
229
+ if (input.tags !== undefined)
230
+ updates.tags = input.tags;
231
+ const deal = await this.storage.update('deals', id, updates);
232
+ return { success: true, data: deal };
233
+ }
234
+ catch (error) {
235
+ return this.handleError(error);
236
+ }
237
+ }
238
+ async deleteDeal(input) {
239
+ try {
240
+ const id = input.id;
241
+ if (!id) {
242
+ return { success: false, error: 'Deal ID is required' };
243
+ }
244
+ const deleted = await this.storage.delete('deals', id);
245
+ return { success: true, data: { id, deleted } };
246
+ }
247
+ catch (error) {
248
+ return this.handleError(error);
249
+ }
250
+ }
251
+ async listDeals(input) {
252
+ try {
253
+ const limit = input.limit ?? 20;
254
+ const offset = input.offset ?? 0;
255
+ const deals = this.storage.list('deals', { limit, offset });
256
+ const total = this.storage.count('deals');
257
+ return { success: true, data: { deals, total } };
258
+ }
259
+ catch (error) {
260
+ return this.handleError(error);
261
+ }
262
+ }
263
+ async getDealsByStage(input) {
264
+ try {
265
+ const stage = input.stage;
266
+ if (!stage) {
267
+ return { success: false, error: 'Stage is required' };
268
+ }
269
+ const deals = this.storage.findByIndex('deals_by_stage', stage);
270
+ return { success: true, data: { deals } };
271
+ }
272
+ catch (error) {
273
+ return this.handleError(error);
274
+ }
275
+ }
276
+ // ============================================================================
277
+ // Activity Handlers
278
+ // ============================================================================
279
+ async createActivity(input) {
280
+ try {
281
+ const type = input.type;
282
+ const title = input.title;
283
+ if (!type)
284
+ return { success: false, error: 'Activity type is required' };
285
+ if (!title)
286
+ return { success: false, error: 'Activity title is required' };
287
+ const activity = await this.storage.insert('activities', {
288
+ contactId: input.contactId,
289
+ dealId: input.dealId,
290
+ type: type,
291
+ title,
292
+ description: input.description ?? '',
293
+ timestamp: input.timestamp ?? new Date().toISOString(),
294
+ duration: input.duration,
295
+ metadata: input.metadata ?? {},
296
+ createdBy: undefined,
297
+ tags: input.tags ?? [],
298
+ customFields: [],
299
+ });
300
+ return { success: true, data: activity };
301
+ }
302
+ catch (error) {
303
+ return this.handleError(error);
304
+ }
305
+ }
306
+ async getActivity(input) {
307
+ try {
308
+ const id = input.id;
309
+ if (!id) {
310
+ return { success: false, error: 'Activity ID is required' };
311
+ }
312
+ const activity = this.storage.get('activities', id);
313
+ if (!activity) {
314
+ return { success: false, error: `Activity not found: ${id}` };
315
+ }
316
+ return { success: true, data: activity };
317
+ }
318
+ catch (error) {
319
+ return this.handleError(error);
320
+ }
321
+ }
322
+ async listActivities(input) {
323
+ try {
324
+ const limit = input.limit ?? 20;
325
+ const offset = input.offset ?? 0;
326
+ const activities = this.storage.list('activities', { limit, offset });
327
+ const total = this.storage.count('activities');
328
+ return { success: true, data: { activities, total } };
329
+ }
330
+ catch (error) {
331
+ return this.handleError(error);
332
+ }
333
+ }
334
+ async deleteActivity(input) {
335
+ try {
336
+ const id = input.id;
337
+ if (!id) {
338
+ return { success: false, error: 'Activity ID is required' };
339
+ }
340
+ const deleted = await this.storage.delete('activities', id);
341
+ return { success: true, data: { id, deleted } };
342
+ }
343
+ catch (error) {
344
+ return this.handleError(error);
345
+ }
346
+ }
347
+ // ============================================================================
348
+ // Media Handlers
349
+ // ============================================================================
350
+ async uploadMedia(input) {
351
+ try {
352
+ const entityType = input.entityType;
353
+ const entityId = input.entityId;
354
+ const type = input.type;
355
+ const filename = input.filename;
356
+ const mimeType = input.mimeType;
357
+ const size = input.size;
358
+ const url = input.url;
359
+ if (!entityType || !entityId || !type || !filename || !mimeType || size === undefined || !url) {
360
+ return { success: false, error: 'Missing required media fields' };
361
+ }
362
+ const media = await this.storage.insert('media', {
363
+ entityType,
364
+ entityId,
365
+ type,
366
+ filename,
367
+ mimeType,
368
+ size,
369
+ url,
370
+ thumbnailUrl: input.thumbnailUrl,
371
+ metadata: input.metadata ?? {},
372
+ altText: input.altText,
373
+ caption: input.caption,
374
+ isPublic: input.isPublic ?? false,
375
+ downloadCount: 0,
376
+ uploadedBy: undefined,
377
+ expiresAt: undefined,
378
+ });
379
+ return { success: true, data: media };
380
+ }
381
+ catch (error) {
382
+ return this.handleError(error);
383
+ }
384
+ }
385
+ async getMedia(input) {
386
+ try {
387
+ const id = input.id;
388
+ if (!id) {
389
+ return { success: false, error: 'Media ID is required' };
390
+ }
391
+ const media = this.storage.get('media', id);
392
+ if (!media) {
393
+ return { success: false, error: `Media not found: ${id}` };
394
+ }
395
+ return { success: true, data: media };
396
+ }
397
+ catch (error) {
398
+ return this.handleError(error);
399
+ }
400
+ }
401
+ async listMedia(input) {
402
+ try {
403
+ const entityId = input.entityId;
404
+ if (!entityId) {
405
+ return { success: false, error: 'Entity ID is required' };
406
+ }
407
+ const media = this.storage.findByIndex('media_by_entity', entityId);
408
+ return { success: true, data: { media } };
409
+ }
410
+ catch (error) {
411
+ return this.handleError(error);
412
+ }
413
+ }
414
+ async deleteMedia(input) {
415
+ try {
416
+ const id = input.id;
417
+ if (!id) {
418
+ return { success: false, error: 'Media ID is required' };
419
+ }
420
+ const deleted = await this.storage.delete('media', id);
421
+ return { success: true, data: { id, deleted } };
422
+ }
423
+ catch (error) {
424
+ return this.handleError(error);
425
+ }
426
+ }
427
+ // ============================================================================
428
+ // Note Handlers
429
+ // ============================================================================
430
+ async createNote(input) {
431
+ try {
432
+ const content = input.content;
433
+ if (!content) {
434
+ return { success: false, error: 'Note content is required' };
435
+ }
436
+ const note = await this.storage.insert('notes', {
437
+ contactId: input.contactId,
438
+ dealId: input.dealId,
439
+ activityId: undefined,
440
+ content,
441
+ format: input.format ?? 'markdown',
442
+ title: input.title,
443
+ visibility: input.visibility ?? 'team',
444
+ createdBy: undefined,
445
+ pinned: input.pinned ?? false,
446
+ tags: input.tags ?? [],
447
+ mediaIds: [],
448
+ });
449
+ return { success: true, data: note };
450
+ }
451
+ catch (error) {
452
+ return this.handleError(error);
453
+ }
454
+ }
455
+ async getNote(input) {
456
+ try {
457
+ const id = input.id;
458
+ if (!id) {
459
+ return { success: false, error: 'Note ID is required' };
460
+ }
461
+ const note = this.storage.get('notes', id);
462
+ if (!note) {
463
+ return { success: false, error: `Note not found: ${id}` };
464
+ }
465
+ return { success: true, data: note };
466
+ }
467
+ catch (error) {
468
+ return this.handleError(error);
469
+ }
470
+ }
471
+ async updateNote(input) {
472
+ try {
473
+ const id = input.id;
474
+ if (!id) {
475
+ return { success: false, error: 'Note ID is required' };
476
+ }
477
+ const updates = {};
478
+ if (input.content !== undefined)
479
+ updates.content = input.content;
480
+ if (input.title !== undefined)
481
+ updates.title = input.title;
482
+ if (input.visibility !== undefined)
483
+ updates.visibility = input.visibility;
484
+ if (input.pinned !== undefined)
485
+ updates.pinned = input.pinned;
486
+ if (input.tags !== undefined)
487
+ updates.tags = input.tags;
488
+ const note = await this.storage.update('notes', id, updates);
489
+ return { success: true, data: note };
490
+ }
491
+ catch (error) {
492
+ return this.handleError(error);
493
+ }
494
+ }
495
+ async deleteNote(input) {
496
+ try {
497
+ const id = input.id;
498
+ if (!id) {
499
+ return { success: false, error: 'Note ID is required' };
500
+ }
501
+ const deleted = await this.storage.delete('notes', id);
502
+ return { success: true, data: { id, deleted } };
503
+ }
504
+ catch (error) {
505
+ return this.handleError(error);
506
+ }
507
+ }
508
+ async listNotes(input) {
509
+ try {
510
+ const limit = input.limit ?? 20;
511
+ const offset = input.offset ?? 0;
512
+ const notes = this.storage.list('notes', { limit, offset });
513
+ const total = this.storage.count('notes');
514
+ return { success: true, data: { notes, total } };
515
+ }
516
+ catch (error) {
517
+ return this.handleError(error);
518
+ }
519
+ }
520
+ // ============================================================================
521
+ // Tag Handlers
522
+ // ============================================================================
523
+ async createTag(input) {
524
+ try {
525
+ const name = input.name;
526
+ const label = input.label;
527
+ const color = input.color;
528
+ if (!name || !label || !color) {
529
+ return { success: false, error: 'Tag name, label, and color are required' };
530
+ }
531
+ const tag = await this.storage.insert('tags', {
532
+ name,
533
+ label,
534
+ color,
535
+ category: input.category ?? 'general',
536
+ description: input.description,
537
+ icon: input.icon,
538
+ usageCount: 0,
539
+ parentId: input.parentId,
540
+ });
541
+ return { success: true, data: tag };
542
+ }
543
+ catch (error) {
544
+ return this.handleError(error);
545
+ }
546
+ }
547
+ async getTag(input) {
548
+ try {
549
+ const id = input.id;
550
+ const name = input.name;
551
+ if (id) {
552
+ const tag = this.storage.get('tags', id);
553
+ if (!tag) {
554
+ return { success: false, error: `Tag not found: ${id}` };
555
+ }
556
+ return { success: true, data: tag };
557
+ }
558
+ if (name) {
559
+ const tags = this.storage.search('tags', 'name', name);
560
+ if (tags.length === 0) {
561
+ return { success: false, error: `Tag not found: ${name}` };
562
+ }
563
+ return { success: true, data: tags[0] };
564
+ }
565
+ return { success: false, error: 'Either id or name is required' };
566
+ }
567
+ catch (error) {
568
+ return this.handleError(error);
569
+ }
570
+ }
571
+ async listTags(input) {
572
+ try {
573
+ let tags = this.storage.list('tags', { limit: 100, offset: 0 });
574
+ if (input.category && typeof input.category === 'string') {
575
+ tags = tags.filter((t) => t.category === input.category);
576
+ }
577
+ return { success: true, data: { tags } };
578
+ }
579
+ catch (error) {
580
+ return this.handleError(error);
581
+ }
582
+ }
583
+ async deleteTag(input) {
584
+ try {
585
+ const id = input.id;
586
+ if (!id) {
587
+ return { success: false, error: 'Tag ID is required' };
588
+ }
589
+ const deleted = await this.storage.delete('tags', id);
590
+ return { success: true, data: { id, deleted } };
591
+ }
592
+ catch (error) {
593
+ return this.handleError(error);
594
+ }
595
+ }
596
+ // ============================================================================
597
+ // Company Handlers
598
+ // ============================================================================
599
+ async createCompany(input) {
600
+ try {
601
+ const name = input.name;
602
+ if (!name) {
603
+ return { success: false, error: 'Company name is required' };
604
+ }
605
+ const company = await this.storage.insert('companies', {
606
+ name,
607
+ website: input.website,
608
+ industry: input.industry,
609
+ size: input.size,
610
+ employeeCount: input.employeeCount,
611
+ annualRevenue: input.annualRevenue,
612
+ currency: undefined,
613
+ address: undefined,
614
+ phone: undefined,
615
+ emailDomain: undefined,
616
+ linkedInUrl: undefined,
617
+ tags: input.tags ?? [],
618
+ customFields: [],
619
+ ownerId: undefined,
620
+ notes: undefined,
621
+ });
622
+ return { success: true, data: company };
623
+ }
624
+ catch (error) {
625
+ return this.handleError(error);
626
+ }
627
+ }
628
+ async getCompany(input) {
629
+ try {
630
+ const id = input.id;
631
+ if (!id) {
632
+ return { success: false, error: 'Company ID is required' };
633
+ }
634
+ const company = this.storage.get('companies', id);
635
+ if (!company) {
636
+ return { success: false, error: `Company not found: ${id}` };
637
+ }
638
+ return { success: true, data: company };
639
+ }
640
+ catch (error) {
641
+ return this.handleError(error);
642
+ }
643
+ }
644
+ async updateCompany(input) {
645
+ try {
646
+ const id = input.id;
647
+ if (!id) {
648
+ return { success: false, error: 'Company ID is required' };
649
+ }
650
+ const updates = {};
651
+ if (input.name !== undefined)
652
+ updates.name = input.name;
653
+ if (input.website !== undefined)
654
+ updates.website = input.website;
655
+ if (input.industry !== undefined)
656
+ updates.industry = input.industry;
657
+ if (input.size !== undefined)
658
+ updates.size = input.size;
659
+ if (input.employeeCount !== undefined)
660
+ updates.employeeCount = input.employeeCount;
661
+ if (input.annualRevenue !== undefined)
662
+ updates.annualRevenue = input.annualRevenue;
663
+ if (input.tags !== undefined)
664
+ updates.tags = input.tags;
665
+ const company = await this.storage.update('companies', id, updates);
666
+ return { success: true, data: company };
667
+ }
668
+ catch (error) {
669
+ return this.handleError(error);
670
+ }
671
+ }
672
+ async deleteCompany(input) {
673
+ try {
674
+ const id = input.id;
675
+ if (!id) {
676
+ return { success: false, error: 'Company ID is required' };
677
+ }
678
+ const deleted = await this.storage.delete('companies', id);
679
+ return { success: true, data: { id, deleted } };
680
+ }
681
+ catch (error) {
682
+ return this.handleError(error);
683
+ }
684
+ }
685
+ async listCompanies(input) {
686
+ try {
687
+ const limit = input.limit ?? 20;
688
+ const offset = input.offset ?? 0;
689
+ let companies = this.storage.list('companies', { limit, offset });
690
+ if (input.industry && typeof input.industry === 'string') {
691
+ companies = companies.filter((c) => c.industry === input.industry);
692
+ }
693
+ const total = this.storage.count('companies');
694
+ return { success: true, data: { companies, total } };
695
+ }
696
+ catch (error) {
697
+ return this.handleError(error);
698
+ }
699
+ }
700
+ // ============================================================================
701
+ // Stats & Dashboard Handlers
702
+ // ============================================================================
703
+ async getStats() {
704
+ try {
705
+ const stats = this.storage.getStats();
706
+ return { success: true, data: stats };
707
+ }
708
+ catch (error) {
709
+ return this.handleError(error);
710
+ }
711
+ }
712
+ async getDashboard(input) {
713
+ try {
714
+ const stats = this.storage.getStats();
715
+ // Get deals by stage
716
+ const stages = ['prospecting', 'qualification', 'needs_analysis', 'proposal', 'negotiation', 'closed_won', 'closed_lost'];
717
+ const dealsByStage = {};
718
+ for (const stage of stages) {
719
+ const deals = this.storage.findByIndex('deals_by_stage', stage);
720
+ dealsByStage[stage] = deals.length;
721
+ }
722
+ // Get recent activities
723
+ const recentActivities = this.storage.list('activities', { limit: 10, offset: 0 });
724
+ return {
725
+ success: true,
726
+ data: {
727
+ stats,
728
+ dealsByStage,
729
+ recentActivities,
730
+ },
731
+ };
732
+ }
733
+ catch (error) {
734
+ return this.handleError(error);
735
+ }
736
+ }
737
+ // ============================================================================
738
+ // Error Handling
739
+ // ============================================================================
740
+ handleError(error) {
741
+ if (error instanceof CRMError) {
742
+ return {
743
+ success: false,
744
+ error: error.message,
745
+ metadata: { code: error.code },
746
+ };
747
+ }
748
+ if (error instanceof Error) {
749
+ return {
750
+ success: false,
751
+ error: error.message,
752
+ };
753
+ }
754
+ return {
755
+ success: false,
756
+ error: String(error),
757
+ };
758
+ }
759
+ }
760
+ //# sourceMappingURL=handlers.js.map