@contractspec/example.crm-pipeline 0.0.0-canary-20260113170453

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 (206) hide show
  1. package/.turbo/turbo-build$colon$bundle.log +172 -0
  2. package/.turbo/turbo-build.log +173 -0
  3. package/CHANGELOG.md +436 -0
  4. package/LICENSE +21 -0
  5. package/README.md +139 -0
  6. package/dist/crm-pipeline.feature.d.ts +12 -0
  7. package/dist/crm-pipeline.feature.d.ts.map +1 -0
  8. package/dist/crm-pipeline.feature.js +166 -0
  9. package/dist/crm-pipeline.feature.js.map +1 -0
  10. package/dist/deal/deal.enum.d.ts +14 -0
  11. package/dist/deal/deal.enum.d.ts.map +1 -0
  12. package/dist/deal/deal.enum.js +25 -0
  13. package/dist/deal/deal.enum.js.map +1 -0
  14. package/dist/deal/deal.operation.d.ts +513 -0
  15. package/dist/deal/deal.operation.d.ts.map +1 -0
  16. package/dist/deal/deal.operation.js +270 -0
  17. package/dist/deal/deal.operation.js.map +1 -0
  18. package/dist/deal/deal.schema.d.ts +300 -0
  19. package/dist/deal/deal.schema.d.ts.map +1 -0
  20. package/dist/deal/deal.schema.js +286 -0
  21. package/dist/deal/deal.schema.js.map +1 -0
  22. package/dist/deal/deal.test-spec.d.ts +8 -0
  23. package/dist/deal/deal.test-spec.d.ts.map +1 -0
  24. package/dist/deal/deal.test-spec.js +65 -0
  25. package/dist/deal/deal.test-spec.js.map +1 -0
  26. package/dist/deal/index.d.ts +4 -0
  27. package/dist/deal/index.js +5 -0
  28. package/dist/docs/crm-pipeline.docblock.d.ts +1 -0
  29. package/dist/docs/crm-pipeline.docblock.js +100 -0
  30. package/dist/docs/crm-pipeline.docblock.js.map +1 -0
  31. package/dist/docs/index.d.ts +1 -0
  32. package/dist/docs/index.js +1 -0
  33. package/dist/entities/company.entity.d.ts +40 -0
  34. package/dist/entities/company.entity.d.ts.map +1 -0
  35. package/dist/entities/company.entity.js +63 -0
  36. package/dist/entities/company.entity.js.map +1 -0
  37. package/dist/entities/contact.entity.d.ts +44 -0
  38. package/dist/entities/contact.entity.d.ts.map +1 -0
  39. package/dist/entities/contact.entity.js +78 -0
  40. package/dist/entities/contact.entity.js.map +1 -0
  41. package/dist/entities/deal.entity.d.ts +73 -0
  42. package/dist/entities/deal.entity.d.ts.map +1 -0
  43. package/dist/entities/deal.entity.js +120 -0
  44. package/dist/entities/deal.entity.js.map +1 -0
  45. package/dist/entities/index.d.ts +15 -0
  46. package/dist/entities/index.d.ts.map +1 -0
  47. package/dist/entities/index.js +33 -0
  48. package/dist/entities/index.js.map +1 -0
  49. package/dist/entities/task.entity.d.ts +65 -0
  50. package/dist/entities/task.entity.d.ts.map +1 -0
  51. package/dist/entities/task.entity.js +129 -0
  52. package/dist/entities/task.entity.js.map +1 -0
  53. package/dist/events/contact.event.d.ts +29 -0
  54. package/dist/events/contact.event.d.ts.map +1 -0
  55. package/dist/events/contact.event.js +45 -0
  56. package/dist/events/contact.event.js.map +1 -0
  57. package/dist/events/deal.event.d.ts +111 -0
  58. package/dist/events/deal.event.d.ts.map +1 -0
  59. package/dist/events/deal.event.js +172 -0
  60. package/dist/events/deal.event.js.map +1 -0
  61. package/dist/events/index.d.ts +4 -0
  62. package/dist/events/index.js +5 -0
  63. package/dist/events/task.event.d.ts +29 -0
  64. package/dist/events/task.event.d.ts.map +1 -0
  65. package/dist/events/task.event.js +45 -0
  66. package/dist/events/task.event.js.map +1 -0
  67. package/dist/example.d.ts +7 -0
  68. package/dist/example.d.ts.map +1 -0
  69. package/dist/example.js +53 -0
  70. package/dist/example.js.map +1 -0
  71. package/dist/handlers/crm.handlers.d.ts +89 -0
  72. package/dist/handlers/crm.handlers.d.ts.map +1 -0
  73. package/dist/handlers/crm.handlers.js +172 -0
  74. package/dist/handlers/crm.handlers.js.map +1 -0
  75. package/dist/handlers/deal.handlers.d.ts +94 -0
  76. package/dist/handlers/deal.handlers.d.ts.map +1 -0
  77. package/dist/handlers/deal.handlers.js +120 -0
  78. package/dist/handlers/deal.handlers.js.map +1 -0
  79. package/dist/handlers/index.d.ts +4 -0
  80. package/dist/handlers/index.js +5 -0
  81. package/dist/handlers/mock-data.d.ts +49 -0
  82. package/dist/handlers/mock-data.d.ts.map +1 -0
  83. package/dist/handlers/mock-data.js +188 -0
  84. package/dist/handlers/mock-data.js.map +1 -0
  85. package/dist/index.d.ts +47 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +56 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/operations/index.d.ts +5 -0
  90. package/dist/operations/index.js +6 -0
  91. package/dist/presentations/dashboard.presentation.d.ts +14 -0
  92. package/dist/presentations/dashboard.presentation.d.ts.map +1 -0
  93. package/dist/presentations/dashboard.presentation.js +62 -0
  94. package/dist/presentations/dashboard.presentation.js.map +1 -0
  95. package/dist/presentations/index.d.ts +3 -0
  96. package/dist/presentations/index.js +4 -0
  97. package/dist/presentations/pipeline.presentation.d.ts +22 -0
  98. package/dist/presentations/pipeline.presentation.d.ts.map +1 -0
  99. package/dist/presentations/pipeline.presentation.js +122 -0
  100. package/dist/presentations/pipeline.presentation.js.map +1 -0
  101. package/dist/seeders/index.d.ts +10 -0
  102. package/dist/seeders/index.d.ts.map +1 -0
  103. package/dist/seeders/index.js +47 -0
  104. package/dist/seeders/index.js.map +1 -0
  105. package/dist/shared/overlay-types.d.ts +34 -0
  106. package/dist/shared/overlay-types.d.ts.map +1 -0
  107. package/dist/shared/overlay-types.js +0 -0
  108. package/dist/ui/CrmDashboard.d.ts +7 -0
  109. package/dist/ui/CrmDashboard.d.ts.map +1 -0
  110. package/dist/ui/CrmDashboard.js +304 -0
  111. package/dist/ui/CrmDashboard.js.map +1 -0
  112. package/dist/ui/CrmDealCard.d.ts +15 -0
  113. package/dist/ui/CrmDealCard.d.ts.map +1 -0
  114. package/dist/ui/CrmDealCard.js +49 -0
  115. package/dist/ui/CrmDealCard.js.map +1 -0
  116. package/dist/ui/CrmPipelineBoard.d.ts +23 -0
  117. package/dist/ui/CrmPipelineBoard.d.ts.map +1 -0
  118. package/dist/ui/CrmPipelineBoard.js +98 -0
  119. package/dist/ui/CrmPipelineBoard.js.map +1 -0
  120. package/dist/ui/hooks/index.d.ts +3 -0
  121. package/dist/ui/hooks/index.js +6 -0
  122. package/dist/ui/hooks/useDealList.d.ts +35 -0
  123. package/dist/ui/hooks/useDealList.d.ts.map +1 -0
  124. package/dist/ui/hooks/useDealList.js +94 -0
  125. package/dist/ui/hooks/useDealList.js.map +1 -0
  126. package/dist/ui/hooks/useDealMutations.d.ts +26 -0
  127. package/dist/ui/hooks/useDealMutations.d.ts.map +1 -0
  128. package/dist/ui/hooks/useDealMutations.js +159 -0
  129. package/dist/ui/hooks/useDealMutations.js.map +1 -0
  130. package/dist/ui/index.d.ts +14 -0
  131. package/dist/ui/index.js +15 -0
  132. package/dist/ui/modals/CreateDealModal.d.ts +33 -0
  133. package/dist/ui/modals/CreateDealModal.d.ts.map +1 -0
  134. package/dist/ui/modals/CreateDealModal.js +183 -0
  135. package/dist/ui/modals/CreateDealModal.js.map +1 -0
  136. package/dist/ui/modals/DealActionsModal.d.ts +51 -0
  137. package/dist/ui/modals/DealActionsModal.d.ts.map +1 -0
  138. package/dist/ui/modals/DealActionsModal.js +372 -0
  139. package/dist/ui/modals/DealActionsModal.js.map +1 -0
  140. package/dist/ui/modals/index.d.ts +3 -0
  141. package/dist/ui/modals/index.js +4 -0
  142. package/dist/ui/overlays/demo-overlays.d.ts +19 -0
  143. package/dist/ui/overlays/demo-overlays.d.ts.map +1 -0
  144. package/dist/ui/overlays/demo-overlays.js +68 -0
  145. package/dist/ui/overlays/demo-overlays.js.map +1 -0
  146. package/dist/ui/overlays/index.d.ts +2 -0
  147. package/dist/ui/overlays/index.js +3 -0
  148. package/dist/ui/renderers/index.d.ts +3 -0
  149. package/dist/ui/renderers/index.js +4 -0
  150. package/dist/ui/renderers/pipeline.markdown.d.ts +23 -0
  151. package/dist/ui/renderers/pipeline.markdown.d.ts.map +1 -0
  152. package/dist/ui/renderers/pipeline.markdown.js +118 -0
  153. package/dist/ui/renderers/pipeline.markdown.js.map +1 -0
  154. package/dist/ui/renderers/pipeline.renderer.d.ts +9 -0
  155. package/dist/ui/renderers/pipeline.renderer.d.ts.map +1 -0
  156. package/dist/ui/renderers/pipeline.renderer.js +28 -0
  157. package/dist/ui/renderers/pipeline.renderer.js.map +1 -0
  158. package/example.ts +1 -0
  159. package/package.json +127 -0
  160. package/src/crm-pipeline.feature.ts +100 -0
  161. package/src/deal/deal.enum.ts +21 -0
  162. package/src/deal/deal.operation.ts +291 -0
  163. package/src/deal/deal.schema.ts +154 -0
  164. package/src/deal/deal.test-spec.ts +55 -0
  165. package/src/deal/index.ts +26 -0
  166. package/src/docs/crm-pipeline.docblock.ts +98 -0
  167. package/src/docs/index.ts +1 -0
  168. package/src/entities/company.entity.ts +77 -0
  169. package/src/entities/contact.entity.ts +93 -0
  170. package/src/entities/deal.entity.ts +160 -0
  171. package/src/entities/index.ts +45 -0
  172. package/src/entities/task.entity.ts +137 -0
  173. package/src/events/contact.event.ts +31 -0
  174. package/src/events/deal.event.ts +104 -0
  175. package/src/events/index.ts +3 -0
  176. package/src/events/task.event.ts +28 -0
  177. package/src/example.ts +38 -0
  178. package/src/handlers/crm.handlers.ts +415 -0
  179. package/src/handlers/deal.handlers.ts +253 -0
  180. package/src/handlers/index.ts +30 -0
  181. package/src/handlers/mock-data.ts +198 -0
  182. package/src/index.ts +32 -0
  183. package/src/operations/index.ts +20 -0
  184. package/src/presentations/dashboard.presentation.ts +59 -0
  185. package/src/presentations/index.ts +2 -0
  186. package/src/presentations/pipeline.presentation.ts +117 -0
  187. package/src/seeders/index.ts +35 -0
  188. package/src/shared/overlay-types.ts +39 -0
  189. package/src/ui/CrmDashboard.tsx +311 -0
  190. package/src/ui/CrmDealCard.tsx +83 -0
  191. package/src/ui/CrmPipelineBoard.tsx +136 -0
  192. package/src/ui/hooks/index.ts +10 -0
  193. package/src/ui/hooks/useDealList.ts +113 -0
  194. package/src/ui/hooks/useDealMutations.ts +174 -0
  195. package/src/ui/index.ts +18 -0
  196. package/src/ui/modals/CreateDealModal.tsx +239 -0
  197. package/src/ui/modals/DealActionsModal.tsx +424 -0
  198. package/src/ui/modals/index.ts +2 -0
  199. package/src/ui/overlays/demo-overlays.ts +68 -0
  200. package/src/ui/overlays/index.ts +1 -0
  201. package/src/ui/renderers/index.ts +6 -0
  202. package/src/ui/renderers/pipeline.markdown.ts +198 -0
  203. package/src/ui/renderers/pipeline.renderer.tsx +35 -0
  204. package/tsconfig.json +10 -0
  205. package/tsconfig.tsbuildinfo +1 -0
  206. package/tsdown.config.js +7 -0
@@ -0,0 +1,172 @@
1
+ import { web } from "@contractspec/lib.runtime-sandbox";
2
+
3
+ //#region src/handlers/crm.handlers.ts
4
+ const { generateId } = web;
5
+ function rowToDeal(row) {
6
+ return {
7
+ id: row.id,
8
+ projectId: row.projectId,
9
+ name: row.name,
10
+ value: row.value,
11
+ currency: row.currency,
12
+ pipelineId: row.pipelineId,
13
+ stageId: row.stageId,
14
+ status: row.status,
15
+ contactId: row.contactId ?? void 0,
16
+ companyId: row.companyId ?? void 0,
17
+ ownerId: row.ownerId,
18
+ expectedCloseDate: row.expectedCloseDate ? new Date(row.expectedCloseDate) : void 0,
19
+ wonSource: row.wonSource ?? void 0,
20
+ lostReason: row.lostReason ?? void 0,
21
+ notes: row.notes ?? void 0,
22
+ createdAt: new Date(row.createdAt),
23
+ updatedAt: new Date(row.updatedAt)
24
+ };
25
+ }
26
+ function createCrmHandlers(db) {
27
+ /**
28
+ * List deals with filtering
29
+ */
30
+ async function listDeals(input) {
31
+ const { projectId, pipelineId, stageId, status, ownerId, search, limit = 20, offset = 0 } = input;
32
+ let whereClause = "WHERE projectId = ?";
33
+ const params = [projectId];
34
+ if (pipelineId) {
35
+ whereClause += " AND pipelineId = ?";
36
+ params.push(pipelineId);
37
+ }
38
+ if (stageId) {
39
+ whereClause += " AND stageId = ?";
40
+ params.push(stageId);
41
+ }
42
+ if (status && status !== "all") {
43
+ whereClause += " AND status = ?";
44
+ params.push(status);
45
+ }
46
+ if (ownerId) {
47
+ whereClause += " AND ownerId = ?";
48
+ params.push(ownerId);
49
+ }
50
+ if (search) {
51
+ whereClause += " AND name LIKE ?";
52
+ params.push(`%${search}%`);
53
+ }
54
+ const total = (await db.query(`SELECT COUNT(*) as count FROM crm_deal ${whereClause}`, params)).rows[0]?.count ?? 0;
55
+ const totalValue = (await db.query(`SELECT COALESCE(SUM(value), 0) as total FROM crm_deal ${whereClause}`, params)).rows[0]?.total ?? 0;
56
+ return {
57
+ deals: (await db.query(`SELECT * FROM crm_deal ${whereClause} ORDER BY value DESC LIMIT ? OFFSET ?`, [
58
+ ...params,
59
+ limit,
60
+ offset
61
+ ])).rows.map(rowToDeal),
62
+ total,
63
+ totalValue
64
+ };
65
+ }
66
+ /**
67
+ * Create a new deal
68
+ */
69
+ async function createDeal(input, context) {
70
+ const id = generateId("deal");
71
+ const now = (/* @__PURE__ */ new Date()).toISOString();
72
+ await db.execute(`INSERT INTO crm_deal (id, projectId, pipelineId, stageId, name, value, currency, status, contactId, companyId, ownerId, expectedCloseDate, createdAt, updatedAt)
73
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
74
+ id,
75
+ context.projectId,
76
+ input.pipelineId,
77
+ input.stageId,
78
+ input.name,
79
+ input.value,
80
+ input.currency ?? "USD",
81
+ "OPEN",
82
+ input.contactId ?? null,
83
+ input.companyId ?? null,
84
+ context.ownerId,
85
+ input.expectedCloseDate?.toISOString() ?? null,
86
+ now,
87
+ now
88
+ ]);
89
+ const rows = (await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [id])).rows;
90
+ if (!rows[0]) throw new Error("Failed to create deal");
91
+ return rowToDeal(rows[0]);
92
+ }
93
+ /**
94
+ * Move a deal to a different stage
95
+ */
96
+ async function moveDeal(input) {
97
+ const now = (/* @__PURE__ */ new Date()).toISOString();
98
+ if (!(await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])).rows[0]) throw new Error("NOT_FOUND");
99
+ if (!(await db.query(`SELECT * FROM crm_stage WHERE id = ?`, [input.stageId])).rows[0]) throw new Error("INVALID_STAGE");
100
+ await db.execute(`UPDATE crm_deal SET stageId = ?, updatedAt = ? WHERE id = ?`, [
101
+ input.stageId,
102
+ now,
103
+ input.dealId
104
+ ]);
105
+ const rows = (await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])).rows;
106
+ return rowToDeal(rows[0]);
107
+ }
108
+ /**
109
+ * Mark a deal as won
110
+ */
111
+ async function winDeal(input) {
112
+ const now = (/* @__PURE__ */ new Date()).toISOString();
113
+ if (!(await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])).rows[0]) throw new Error("NOT_FOUND");
114
+ await db.execute(`UPDATE crm_deal SET status = 'WON', wonSource = ?, notes = ?, updatedAt = ? WHERE id = ?`, [
115
+ input.wonSource ?? null,
116
+ input.notes ?? null,
117
+ now,
118
+ input.dealId
119
+ ]);
120
+ const rows = (await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])).rows;
121
+ return rowToDeal(rows[0]);
122
+ }
123
+ /**
124
+ * Mark a deal as lost
125
+ */
126
+ async function loseDeal(input) {
127
+ const now = (/* @__PURE__ */ new Date()).toISOString();
128
+ if (!(await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])).rows[0]) throw new Error("NOT_FOUND");
129
+ await db.execute(`UPDATE crm_deal SET status = 'LOST', lostReason = ?, notes = ?, updatedAt = ? WHERE id = ?`, [
130
+ input.lostReason,
131
+ input.notes ?? null,
132
+ now,
133
+ input.dealId
134
+ ]);
135
+ const rows = (await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])).rows;
136
+ return rowToDeal(rows[0]);
137
+ }
138
+ /**
139
+ * Get deals grouped by stage
140
+ */
141
+ async function getDealsByStage(input) {
142
+ const deals = (await db.query(`SELECT * FROM crm_deal WHERE projectId = ? AND pipelineId = ? AND status = 'OPEN' ORDER BY value DESC`, [input.projectId, input.pipelineId])).rows;
143
+ const stages = (await db.query(`SELECT * FROM crm_stage WHERE pipelineId = ? ORDER BY position`, [input.pipelineId])).rows;
144
+ const grouped = {};
145
+ for (const stage of stages) grouped[stage.id] = deals.filter((d) => d.stageId === stage.id).map(rowToDeal);
146
+ return grouped;
147
+ }
148
+ /**
149
+ * Get pipeline stages
150
+ */
151
+ async function getPipelineStages(input) {
152
+ return (await db.query(`SELECT * FROM crm_stage WHERE pipelineId = ? ORDER BY position`, [input.pipelineId])).rows.map((row) => ({
153
+ id: row.id,
154
+ pipelineId: row.pipelineId,
155
+ name: row.name,
156
+ position: row.position
157
+ }));
158
+ }
159
+ return {
160
+ listDeals,
161
+ createDeal,
162
+ moveDeal,
163
+ winDeal,
164
+ loseDeal,
165
+ getDealsByStage,
166
+ getPipelineStages
167
+ };
168
+ }
169
+
170
+ //#endregion
171
+ export { createCrmHandlers };
172
+ //# sourceMappingURL=crm.handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crm.handlers.js","names":[],"sources":["../../src/handlers/crm.handlers.ts"],"sourcesContent":["/**\n * Runtime-local CRM handlers\n *\n * These handlers work with the in-browser SQLite database\n * instead of in-memory mock arrays.\n */\nimport type { DatabasePort, DbRow } from '@contractspec/lib.runtime-sandbox';\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { web } from '@contractspec/lib.runtime-sandbox';\nconst { generateId } = web;\n\n// ============ Types ============\n\nexport interface Deal {\n id: string;\n projectId: string;\n name: string;\n value: number;\n currency: string;\n pipelineId: string;\n stageId: string;\n status: 'OPEN' | 'WON' | 'LOST' | 'STALE';\n contactId?: string;\n companyId?: string;\n ownerId: string;\n expectedCloseDate?: Date;\n wonSource?: string;\n lostReason?: string;\n notes?: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface Stage {\n id: string;\n pipelineId: string;\n name: string;\n position: number;\n}\n\nexport interface CreateDealInput {\n name: string;\n value: number;\n currency?: string;\n pipelineId: string;\n stageId: string;\n contactId?: string;\n companyId?: string;\n expectedCloseDate?: Date;\n}\n\nexport interface MoveDealInput {\n dealId: string;\n stageId: string;\n}\n\nexport interface WinDealInput {\n dealId: string;\n wonSource?: string;\n notes?: string;\n}\n\nexport interface LoseDealInput {\n dealId: string;\n lostReason: string;\n notes?: string;\n}\n\nexport interface ListDealsInput {\n projectId: string;\n pipelineId?: string;\n stageId?: string;\n status?: 'OPEN' | 'WON' | 'LOST' | 'all';\n ownerId?: string;\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface ListDealsOutput {\n deals: Deal[];\n total: number;\n totalValue: number;\n}\n\n// ============ Row Type ============\n\n// Note: We don't use DbRow generics here - just cast the results\n// to the expected types since we know the schema\n\ninterface DealRow {\n id: string;\n projectId: string;\n name: string;\n value: number;\n currency: string;\n pipelineId: string;\n stageId: string;\n status: string;\n contactId: string | null;\n companyId: string | null;\n ownerId: string;\n expectedCloseDate: string | null;\n wonSource: string | null;\n lostReason: string | null;\n notes: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface StageRow {\n id: string;\n pipelineId: string;\n name: string;\n position: number;\n}\n\nfunction rowToDeal(row: DealRow): Deal {\n return {\n id: row.id,\n projectId: row.projectId,\n name: row.name,\n value: row.value,\n currency: row.currency,\n pipelineId: row.pipelineId,\n stageId: row.stageId,\n status: row.status as Deal['status'],\n contactId: row.contactId ?? undefined,\n companyId: row.companyId ?? undefined,\n ownerId: row.ownerId,\n expectedCloseDate: row.expectedCloseDate\n ? new Date(row.expectedCloseDate)\n : undefined,\n wonSource: row.wonSource ?? undefined,\n lostReason: row.lostReason ?? undefined,\n notes: row.notes ?? undefined,\n createdAt: new Date(row.createdAt),\n updatedAt: new Date(row.updatedAt),\n };\n}\n\n// ============ Handler Factory ============\n\nexport function createCrmHandlers(db: DatabasePort) {\n /**\n * List deals with filtering\n */\n async function listDeals(input: ListDealsInput): Promise<ListDealsOutput> {\n const {\n projectId,\n pipelineId,\n stageId,\n status,\n ownerId,\n search,\n limit = 20,\n offset = 0,\n } = input;\n\n let whereClause = 'WHERE projectId = ?';\n const params: (string | number)[] = [projectId];\n\n if (pipelineId) {\n whereClause += ' AND pipelineId = ?';\n params.push(pipelineId);\n }\n\n if (stageId) {\n whereClause += ' AND stageId = ?';\n params.push(stageId);\n }\n\n if (status && status !== 'all') {\n whereClause += ' AND status = ?';\n params.push(status);\n }\n\n if (ownerId) {\n whereClause += ' AND ownerId = ?';\n params.push(ownerId);\n }\n\n if (search) {\n whereClause += ' AND name LIKE ?';\n params.push(`%${search}%`);\n }\n\n // Get total count\n const countResult = (\n await db.query(\n `SELECT COUNT(*) as count FROM crm_deal ${whereClause}`,\n params\n )\n ).rows as DbRow[];\n const total = (countResult[0]?.count as number) ?? 0;\n\n // Get total value\n const valueResult = (\n await db.query(\n `SELECT COALESCE(SUM(value), 0) as total FROM crm_deal ${whereClause}`,\n params\n )\n ).rows as DbRow[];\n const totalValue = (valueResult[0]?.total as number) ?? 0;\n\n // Get paginated deals\n const dealRows = (\n await db.query(\n `SELECT * FROM crm_deal ${whereClause} ORDER BY value DESC LIMIT ? OFFSET ?`,\n [...params, limit, offset]\n )\n ).rows as unknown as DealRow[];\n\n return {\n deals: dealRows.map(rowToDeal),\n total,\n totalValue,\n };\n }\n\n /**\n * Create a new deal\n */\n async function createDeal(\n input: CreateDealInput,\n context: { projectId: string; ownerId: string }\n ): Promise<Deal> {\n const id = generateId('deal');\n const now = new Date().toISOString();\n\n await db.execute(\n `INSERT INTO crm_deal (id, projectId, pipelineId, stageId, name, value, currency, status, contactId, companyId, ownerId, expectedCloseDate, createdAt, updatedAt)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n context.projectId,\n input.pipelineId,\n input.stageId,\n input.name,\n input.value,\n input.currency ?? 'USD',\n 'OPEN',\n input.contactId ?? null,\n input.companyId ?? null,\n context.ownerId,\n input.expectedCloseDate?.toISOString() ?? null,\n now,\n now,\n ]\n );\n\n const rows = (await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [id]))\n .rows as unknown as DealRow[];\n\n if (!rows[0]) {\n throw new Error('Failed to create deal');\n }\n\n return rowToDeal(rows[0]);\n }\n\n /**\n * Move a deal to a different stage\n */\n async function moveDeal(input: MoveDealInput): Promise<Deal> {\n const now = new Date().toISOString();\n\n // Verify deal exists\n const existing = (\n await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])\n ).rows as unknown as DealRow[];\n\n if (!existing[0]) {\n throw new Error('NOT_FOUND');\n }\n\n // Verify stage exists\n const stage = (\n await db.query(`SELECT * FROM crm_stage WHERE id = ?`, [input.stageId])\n ).rows as unknown as StageRow[];\n\n if (!stage[0]) {\n throw new Error('INVALID_STAGE');\n }\n\n await db.execute(\n `UPDATE crm_deal SET stageId = ?, updatedAt = ? WHERE id = ?`,\n [input.stageId, now, input.dealId]\n );\n\n const rows = (\n await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])\n ).rows as unknown as DealRow[];\n\n return rowToDeal(rows[0]!);\n }\n\n /**\n * Mark a deal as won\n */\n async function winDeal(input: WinDealInput): Promise<Deal> {\n const now = new Date().toISOString();\n\n // Verify deal exists\n const existing = (\n await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])\n ).rows as unknown as DealRow[];\n\n if (!existing[0]) {\n throw new Error('NOT_FOUND');\n }\n\n await db.execute(\n `UPDATE crm_deal SET status = 'WON', wonSource = ?, notes = ?, updatedAt = ? WHERE id = ?`,\n [input.wonSource ?? null, input.notes ?? null, now, input.dealId]\n );\n\n const rows = (\n await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])\n ).rows as unknown as DealRow[];\n\n return rowToDeal(rows[0]!);\n }\n\n /**\n * Mark a deal as lost\n */\n async function loseDeal(input: LoseDealInput): Promise<Deal> {\n const now = new Date().toISOString();\n\n // Verify deal exists\n const existing = (\n await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])\n ).rows as unknown as DealRow[];\n\n if (!existing[0]) {\n throw new Error('NOT_FOUND');\n }\n\n await db.execute(\n `UPDATE crm_deal SET status = 'LOST', lostReason = ?, notes = ?, updatedAt = ? WHERE id = ?`,\n [input.lostReason, input.notes ?? null, now, input.dealId]\n );\n\n const rows = (\n await db.query(`SELECT * FROM crm_deal WHERE id = ?`, [input.dealId])\n ).rows as unknown as DealRow[];\n\n return rowToDeal(rows[0]!);\n }\n\n /**\n * Get deals grouped by stage\n */\n async function getDealsByStage(input: {\n projectId: string;\n pipelineId: string;\n }): Promise<Record<string, Deal[]>> {\n const deals = (\n await db.query(\n `SELECT * FROM crm_deal WHERE projectId = ? AND pipelineId = ? AND status = 'OPEN' ORDER BY value DESC`,\n [input.projectId, input.pipelineId]\n )\n ).rows as unknown as DealRow[];\n\n const stages = (\n await db.query(\n `SELECT * FROM crm_stage WHERE pipelineId = ? ORDER BY position`,\n [input.pipelineId]\n )\n ).rows as unknown as StageRow[];\n\n const grouped: Record<string, Deal[]> = {};\n for (const stage of stages) {\n grouped[stage.id] = deals\n .filter((d) => d.stageId === stage.id)\n .map(rowToDeal);\n }\n\n return grouped;\n }\n\n /**\n * Get pipeline stages\n */\n async function getPipelineStages(input: {\n pipelineId: string;\n }): Promise<Stage[]> {\n const rows = (\n await db.query(\n `SELECT * FROM crm_stage WHERE pipelineId = ? ORDER BY position`,\n [input.pipelineId]\n )\n ).rows as unknown as StageRow[];\n\n return rows.map((row) => ({\n id: row.id,\n pipelineId: row.pipelineId,\n name: row.name,\n position: row.position,\n }));\n }\n\n return {\n listDeals,\n createDeal,\n moveDeal,\n winDeal,\n loseDeal,\n getDealsByStage,\n getPipelineStages,\n };\n}\n\nexport type CrmHandlers = ReturnType<typeof createCrmHandlers>;\n"],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { MockStage } from "./mock-data.js";
2
+
3
+ //#region src/handlers/deal.handlers.d.ts
4
+ interface Deal {
5
+ id: string;
6
+ name: string;
7
+ value: number;
8
+ currency: string;
9
+ pipelineId: string;
10
+ stageId: string;
11
+ status: 'OPEN' | 'WON' | 'LOST' | 'STALE';
12
+ contactId?: string;
13
+ companyId?: string;
14
+ ownerId: string;
15
+ expectedCloseDate?: Date;
16
+ createdAt: Date;
17
+ updatedAt: Date;
18
+ }
19
+ interface CreateDealInput {
20
+ name: string;
21
+ value: number;
22
+ currency?: string;
23
+ pipelineId: string;
24
+ stageId: string;
25
+ contactId?: string;
26
+ companyId?: string;
27
+ expectedCloseDate?: Date;
28
+ }
29
+ interface MoveDealInput {
30
+ dealId: string;
31
+ stageId: string;
32
+ position?: number;
33
+ }
34
+ interface WinDealInput {
35
+ dealId: string;
36
+ wonSource?: string;
37
+ notes?: string;
38
+ }
39
+ interface LoseDealInput {
40
+ dealId: string;
41
+ lostReason: string;
42
+ notes?: string;
43
+ }
44
+ interface ListDealsInput {
45
+ pipelineId?: string;
46
+ stageId?: string;
47
+ status?: 'OPEN' | 'WON' | 'LOST' | 'all';
48
+ ownerId?: string;
49
+ search?: string;
50
+ limit?: number;
51
+ offset?: number;
52
+ }
53
+ interface ListDealsOutput {
54
+ deals: Deal[];
55
+ total: number;
56
+ totalValue: number;
57
+ }
58
+ /**
59
+ * Mock handler for ListDealsContract
60
+ */
61
+ declare function mockListDealsHandler(input: ListDealsInput): Promise<ListDealsOutput>;
62
+ /**
63
+ * Mock handler for CreateDealContract
64
+ */
65
+ declare function mockCreateDealHandler(input: CreateDealInput, context: {
66
+ ownerId: string;
67
+ }): Promise<Deal>;
68
+ /**
69
+ * Mock handler for MoveDealContract
70
+ */
71
+ declare function mockMoveDealHandler(input: MoveDealInput): Promise<Deal>;
72
+ /**
73
+ * Mock handler for WinDealContract
74
+ */
75
+ declare function mockWinDealHandler(input: WinDealInput): Promise<Deal>;
76
+ /**
77
+ * Mock handler for LoseDealContract
78
+ */
79
+ declare function mockLoseDealHandler(input: LoseDealInput): Promise<Deal>;
80
+ /**
81
+ * Get deals grouped by stage for Kanban view
82
+ */
83
+ declare function mockGetDealsByStageHandler(input: {
84
+ pipelineId: string;
85
+ }): Promise<Record<string, Deal[]>>;
86
+ /**
87
+ * Get pipeline stages
88
+ */
89
+ declare function mockGetPipelineStagesHandler(input: {
90
+ pipelineId: string;
91
+ }): Promise<MockStage[]>;
92
+ //#endregion
93
+ export { CreateDealInput, Deal, ListDealsInput, ListDealsOutput, LoseDealInput, MoveDealInput, WinDealInput, mockCreateDealHandler, mockGetDealsByStageHandler, mockGetPipelineStagesHandler, mockListDealsHandler, mockLoseDealHandler, mockMoveDealHandler, mockWinDealHandler };
94
+ //# sourceMappingURL=deal.handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deal.handlers.d.ts","names":[],"sources":["../../src/handlers/deal.handlers.ts"],"sourcesContent":[],"mappings":";;;UAMiB,IAAA;;;EAAA,KAAA,EAAI,MAAA;EAWC,QAAA,EAAA,MAAA;EACT,UAAA,EAAA,MAAA;EACA,OAAA,EAAA,MAAA;EAAI,MAAA,EAAA,MAAA,GAAA,KAAA,GAAA,MAAA,GAAA,OAAA;EAGA,SAAA,CAAA,EAAA,MAAe;EAWf,SAAA,CAAA,EAAA,MAAa;EAMb,OAAA,EAAA,MAAY;EAMZ,iBAAa,CAAA,EA5BR,IA4BQ;EAMb,SAAA,EAjCJ,IAiCI;EAUA,SAAA,EA1CJ,IA0CI;AASjB;AACS,UAjDQ,eAAA,CAiDR;EACE,IAAA,EAAA,MAAA;EAAR,KAAA,EAAA,MAAA;EAAO,QAAA,CAAA,EAAA,MAAA;EAmDY,UAAA,EAAA,MAAA;EACb,OAAA,EAAA,MAAA;EAEE,SAAA,CAAA,EAAA,MAAA;EAAR,SAAA,CAAA,EAAA,MAAA;EAAO,iBAAA,CAAA,EAhGY,IAgGZ;AA2BV;AAAiD,UAxHhC,aAAA,CAwHgC;EAAwB,MAAA,EAAA,MAAA;EAAR,OAAA,EAAA,MAAA;EAAO,QAAA,CAAA,EAAA,MAAA;AA6BxE;AAAgD,UA/I/B,YAAA,CA+I+B;EAAuB,MAAA,EAAA,MAAA;EAAR,SAAA,CAAA,EAAA,MAAA;EAAO,KAAA,CAAA,EAAA,MAAA;AAwBtE;AAAiD,UAjKhC,aAAA,CAiKgC;EAAwB,MAAA,EAAA,MAAA;EAAR,UAAA,EAAA,MAAA;EAAO,KAAA,CAAA,EAAA,MAAA;AAwBxE;AAE2B,UArLV,cAAA,CAqLU;EAAf,UAAA,CAAA,EAAA,MAAA;EAAR,OAAA,CAAA,EAAA,MAAA;EAAO,MAAA,CAAA,EAAA,MAAA,GAAA,KAAA,GAAA,MAAA,GAAA,KAAA;EAgBW,OAAA,CAAA,EAAA,MAAA;;;;;UA3LL,eAAA;SACR;;;;;;;iBAQa,oBAAA,QACb,iBACN,QAAQ;;;;iBAmDW,qBAAA,QACb;;IAEN,QAAQ;;;;iBA2BW,mBAAA,QAA2B,gBAAgB,QAAQ;;;;iBA6BnD,kBAAA,QAA0B,eAAe,QAAQ;;;;iBAwBjD,mBAAA,QAA2B,gBAAgB,QAAQ;;;;iBAwBnD,0BAAA;;IAElB,QAAQ,eAAe;;;;iBAgBL,4BAAA;;IAErB,QAFiD,SAAA"}
@@ -0,0 +1,120 @@
1
+ import { MOCK_DEALS, MOCK_STAGES } from "./mock-data.js";
2
+
3
+ //#region src/handlers/deal.handlers.ts
4
+ /**
5
+ * Mock handlers for Deal contracts
6
+ */
7
+ /**
8
+ * Mock handler for ListDealsContract
9
+ */
10
+ async function mockListDealsHandler(input) {
11
+ const { pipelineId, stageId, status, ownerId, search, limit = 20, offset = 0 } = input;
12
+ let filtered = [...MOCK_DEALS];
13
+ if (pipelineId) filtered = filtered.filter((d) => d.pipelineId === pipelineId);
14
+ if (stageId) filtered = filtered.filter((d) => d.stageId === stageId);
15
+ if (status && status !== "all") filtered = filtered.filter((d) => d.status === status);
16
+ if (ownerId) filtered = filtered.filter((d) => d.ownerId === ownerId);
17
+ if (search) {
18
+ const q = search.toLowerCase();
19
+ filtered = filtered.filter((d) => d.name.toLowerCase().includes(q));
20
+ }
21
+ filtered.sort((a, b) => b.value - a.value);
22
+ const total = filtered.length;
23
+ const totalValue = filtered.reduce((sum, d) => sum + d.value, 0);
24
+ return {
25
+ deals: filtered.slice(offset, offset + limit),
26
+ total,
27
+ totalValue
28
+ };
29
+ }
30
+ /**
31
+ * Mock handler for CreateDealContract
32
+ */
33
+ async function mockCreateDealHandler(input, context) {
34
+ const now = /* @__PURE__ */ new Date();
35
+ const deal = {
36
+ id: `deal-${Date.now()}`,
37
+ name: input.name,
38
+ value: input.value,
39
+ currency: input.currency ?? "USD",
40
+ pipelineId: input.pipelineId,
41
+ stageId: input.stageId,
42
+ status: "OPEN",
43
+ contactId: input.contactId,
44
+ companyId: input.companyId,
45
+ ownerId: context.ownerId,
46
+ expectedCloseDate: input.expectedCloseDate,
47
+ createdAt: now,
48
+ updatedAt: now
49
+ };
50
+ MOCK_DEALS.push(deal);
51
+ return deal;
52
+ }
53
+ /**
54
+ * Mock handler for MoveDealContract
55
+ */
56
+ async function mockMoveDealHandler(input) {
57
+ const dealIndex = MOCK_DEALS.findIndex((d) => d.id === input.dealId);
58
+ if (dealIndex === -1) throw new Error("NOT_FOUND");
59
+ const deal = MOCK_DEALS[dealIndex];
60
+ if (!deal) throw new Error("NOT_FOUND");
61
+ if (!MOCK_STAGES.find((s) => s.id === input.stageId)) throw new Error("INVALID_STAGE");
62
+ const updatedDeal = {
63
+ ...deal,
64
+ stageId: input.stageId,
65
+ updatedAt: /* @__PURE__ */ new Date()
66
+ };
67
+ MOCK_DEALS[dealIndex] = updatedDeal;
68
+ return updatedDeal;
69
+ }
70
+ /**
71
+ * Mock handler for WinDealContract
72
+ */
73
+ async function mockWinDealHandler(input) {
74
+ const dealIndex = MOCK_DEALS.findIndex((d) => d.id === input.dealId);
75
+ if (dealIndex === -1) throw new Error("NOT_FOUND");
76
+ const deal = MOCK_DEALS[dealIndex];
77
+ if (!deal) throw new Error("NOT_FOUND");
78
+ const updatedDeal = {
79
+ ...deal,
80
+ status: "WON",
81
+ updatedAt: /* @__PURE__ */ new Date()
82
+ };
83
+ MOCK_DEALS[dealIndex] = updatedDeal;
84
+ return updatedDeal;
85
+ }
86
+ /**
87
+ * Mock handler for LoseDealContract
88
+ */
89
+ async function mockLoseDealHandler(input) {
90
+ const dealIndex = MOCK_DEALS.findIndex((d) => d.id === input.dealId);
91
+ if (dealIndex === -1) throw new Error("NOT_FOUND");
92
+ const deal = MOCK_DEALS[dealIndex];
93
+ if (!deal) throw new Error("NOT_FOUND");
94
+ const updatedDeal = {
95
+ ...deal,
96
+ status: "LOST",
97
+ updatedAt: /* @__PURE__ */ new Date()
98
+ };
99
+ MOCK_DEALS[dealIndex] = updatedDeal;
100
+ return updatedDeal;
101
+ }
102
+ /**
103
+ * Get deals grouped by stage for Kanban view
104
+ */
105
+ async function mockGetDealsByStageHandler(input) {
106
+ const deals = MOCK_DEALS.filter((d) => d.pipelineId === input.pipelineId && d.status === "OPEN");
107
+ const grouped = {};
108
+ for (const stage of MOCK_STAGES) grouped[stage.id] = deals.filter((d) => d.stageId === stage.id);
109
+ return grouped;
110
+ }
111
+ /**
112
+ * Get pipeline stages
113
+ */
114
+ async function mockGetPipelineStagesHandler(input) {
115
+ return MOCK_STAGES.filter((s) => s.pipelineId === input.pipelineId);
116
+ }
117
+
118
+ //#endregion
119
+ export { mockCreateDealHandler, mockGetDealsByStageHandler, mockGetPipelineStagesHandler, mockListDealsHandler, mockLoseDealHandler, mockMoveDealHandler, mockWinDealHandler };
120
+ //# sourceMappingURL=deal.handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deal.handlers.js","names":[],"sources":["../../src/handlers/deal.handlers.ts"],"sourcesContent":["/**\n * Mock handlers for Deal contracts\n */\nimport { MOCK_DEALS, MOCK_STAGES } from './mock-data';\n\n// Types inferred from contract schemas\nexport interface Deal {\n id: string;\n name: string;\n value: number;\n currency: string;\n pipelineId: string;\n stageId: string;\n status: 'OPEN' | 'WON' | 'LOST' | 'STALE';\n contactId?: string;\n companyId?: string;\n ownerId: string;\n expectedCloseDate?: Date;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateDealInput {\n name: string;\n value: number;\n currency?: string;\n pipelineId: string;\n stageId: string;\n contactId?: string;\n companyId?: string;\n expectedCloseDate?: Date;\n}\n\nexport interface MoveDealInput {\n dealId: string;\n stageId: string;\n position?: number;\n}\n\nexport interface WinDealInput {\n dealId: string;\n wonSource?: string;\n notes?: string;\n}\n\nexport interface LoseDealInput {\n dealId: string;\n lostReason: string;\n notes?: string;\n}\n\nexport interface ListDealsInput {\n pipelineId?: string;\n stageId?: string;\n status?: 'OPEN' | 'WON' | 'LOST' | 'all';\n ownerId?: string;\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface ListDealsOutput {\n deals: Deal[];\n total: number;\n totalValue: number;\n}\n\n/**\n * Mock handler for ListDealsContract\n */\nexport async function mockListDealsHandler(\n input: ListDealsInput\n): Promise<ListDealsOutput> {\n const {\n pipelineId,\n stageId,\n status,\n ownerId,\n search,\n limit = 20,\n offset = 0,\n } = input;\n\n let filtered = [...MOCK_DEALS];\n\n if (pipelineId) {\n filtered = filtered.filter((d) => d.pipelineId === pipelineId);\n }\n\n if (stageId) {\n filtered = filtered.filter((d) => d.stageId === stageId);\n }\n\n if (status && status !== 'all') {\n filtered = filtered.filter((d) => d.status === status);\n }\n\n if (ownerId) {\n filtered = filtered.filter((d) => d.ownerId === ownerId);\n }\n\n if (search) {\n const q = search.toLowerCase();\n filtered = filtered.filter((d) => d.name.toLowerCase().includes(q));\n }\n\n // Sort by value descending\n filtered.sort((a, b) => b.value - a.value);\n\n const total = filtered.length;\n const totalValue = filtered.reduce((sum, d) => sum + d.value, 0);\n const deals = filtered.slice(offset, offset + limit);\n\n return {\n deals,\n total,\n totalValue,\n };\n}\n\n/**\n * Mock handler for CreateDealContract\n */\nexport async function mockCreateDealHandler(\n input: CreateDealInput,\n context: { ownerId: string }\n): Promise<Deal> {\n const now = new Date();\n\n const deal: Deal = {\n id: `deal-${Date.now()}`,\n name: input.name,\n value: input.value,\n currency: input.currency ?? 'USD',\n pipelineId: input.pipelineId,\n stageId: input.stageId,\n status: 'OPEN',\n contactId: input.contactId,\n companyId: input.companyId,\n ownerId: context.ownerId,\n expectedCloseDate: input.expectedCloseDate,\n createdAt: now,\n updatedAt: now,\n };\n\n MOCK_DEALS.push(deal);\n\n return deal;\n}\n\n/**\n * Mock handler for MoveDealContract\n */\nexport async function mockMoveDealHandler(input: MoveDealInput): Promise<Deal> {\n const dealIndex = MOCK_DEALS.findIndex((d) => d.id === input.dealId);\n if (dealIndex === -1) {\n throw new Error('NOT_FOUND');\n }\n const deal = MOCK_DEALS[dealIndex];\n if (!deal) {\n throw new Error('NOT_FOUND');\n }\n\n const stage = MOCK_STAGES.find((s) => s.id === input.stageId);\n if (!stage) {\n throw new Error('INVALID_STAGE');\n }\n\n const updatedDeal: Deal = {\n ...deal,\n stageId: input.stageId,\n updatedAt: new Date(),\n };\n\n MOCK_DEALS[dealIndex] = updatedDeal;\n\n return updatedDeal;\n}\n\n/**\n * Mock handler for WinDealContract\n */\nexport async function mockWinDealHandler(input: WinDealInput): Promise<Deal> {\n const dealIndex = MOCK_DEALS.findIndex((d) => d.id === input.dealId);\n if (dealIndex === -1) {\n throw new Error('NOT_FOUND');\n }\n const deal = MOCK_DEALS[dealIndex];\n if (!deal) {\n throw new Error('NOT_FOUND');\n }\n\n const updatedDeal: Deal = {\n ...deal,\n status: 'WON' as const,\n updatedAt: new Date(),\n };\n\n MOCK_DEALS[dealIndex] = updatedDeal;\n\n return updatedDeal;\n}\n\n/**\n * Mock handler for LoseDealContract\n */\nexport async function mockLoseDealHandler(input: LoseDealInput): Promise<Deal> {\n const dealIndex = MOCK_DEALS.findIndex((d) => d.id === input.dealId);\n if (dealIndex === -1) {\n throw new Error('NOT_FOUND');\n }\n const deal = MOCK_DEALS[dealIndex];\n if (!deal) {\n throw new Error('NOT_FOUND');\n }\n\n const updatedDeal: Deal = {\n ...deal,\n status: 'LOST' as const,\n updatedAt: new Date(),\n };\n\n MOCK_DEALS[dealIndex] = updatedDeal;\n\n return updatedDeal;\n}\n\n/**\n * Get deals grouped by stage for Kanban view\n */\nexport async function mockGetDealsByStageHandler(input: {\n pipelineId: string;\n}): Promise<Record<string, Deal[]>> {\n const deals = MOCK_DEALS.filter(\n (d) => d.pipelineId === input.pipelineId && d.status === 'OPEN'\n );\n\n const grouped: Record<string, Deal[]> = {};\n for (const stage of MOCK_STAGES) {\n grouped[stage.id] = deals.filter((d) => d.stageId === stage.id);\n }\n\n return grouped;\n}\n\n/**\n * Get pipeline stages\n */\nexport async function mockGetPipelineStagesHandler(input: {\n pipelineId: string;\n}) {\n return MOCK_STAGES.filter((s) => s.pipelineId === input.pipelineId);\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { CrmHandlers, Stage, createCrmHandlers } from "./crm.handlers.js";
2
+ import { MOCK_COMPANIES, MOCK_CONTACTS, MOCK_DEALS, MOCK_STAGES, MockDeal, MockStage } from "./mock-data.js";
3
+ import { CreateDealInput, Deal, ListDealsInput, ListDealsOutput, LoseDealInput, MoveDealInput, WinDealInput, mockCreateDealHandler, mockGetDealsByStageHandler, mockGetPipelineStagesHandler, mockListDealsHandler, mockLoseDealHandler, mockMoveDealHandler, mockWinDealHandler } from "./deal.handlers.js";
4
+ export { type CreateDealInput, CrmHandlers, type Deal, type ListDealsInput, type ListDealsOutput, type LoseDealInput, MOCK_COMPANIES, MOCK_CONTACTS, MOCK_DEALS, MOCK_STAGES, MockDeal, MockStage, type MoveDealInput, Stage, type WinDealInput, createCrmHandlers, mockCreateDealHandler, mockGetDealsByStageHandler, mockGetPipelineStagesHandler, mockListDealsHandler, mockLoseDealHandler, mockMoveDealHandler, mockWinDealHandler };
@@ -0,0 +1,5 @@
1
+ import { MOCK_COMPANIES, MOCK_CONTACTS, MOCK_DEALS, MOCK_STAGES } from "./mock-data.js";
2
+ import { mockCreateDealHandler, mockGetDealsByStageHandler, mockGetPipelineStagesHandler, mockListDealsHandler, mockLoseDealHandler, mockMoveDealHandler, mockWinDealHandler } from "./deal.handlers.js";
3
+ import { createCrmHandlers } from "./crm.handlers.js";
4
+
5
+ export { MOCK_COMPANIES, MOCK_CONTACTS, MOCK_DEALS, MOCK_STAGES, createCrmHandlers, mockCreateDealHandler, mockGetDealsByStageHandler, mockGetPipelineStagesHandler, mockListDealsHandler, mockLoseDealHandler, mockMoveDealHandler, mockWinDealHandler };
@@ -0,0 +1,49 @@
1
+ //#region src/handlers/mock-data.d.ts
2
+ /**
3
+ * Mock data for crm-pipeline handlers
4
+ */
5
+ interface MockDeal {
6
+ id: string;
7
+ name: string;
8
+ value: number;
9
+ currency: string;
10
+ pipelineId: string;
11
+ stageId: string;
12
+ status: 'OPEN' | 'WON' | 'LOST' | 'STALE';
13
+ contactId?: string;
14
+ companyId?: string;
15
+ ownerId: string;
16
+ expectedCloseDate?: Date;
17
+ createdAt: Date;
18
+ updatedAt: Date;
19
+ }
20
+ interface MockStage {
21
+ id: string;
22
+ name: string;
23
+ position: number;
24
+ pipelineId: string;
25
+ }
26
+ declare const MOCK_STAGES: MockStage[];
27
+ declare const MOCK_DEALS: MockDeal[];
28
+ declare const MOCK_COMPANIES: {
29
+ id: string;
30
+ name: string;
31
+ domain: string;
32
+ industry: string;
33
+ size: string;
34
+ website: string;
35
+ createdAt: Date;
36
+ }[];
37
+ declare const MOCK_CONTACTS: {
38
+ id: string;
39
+ firstName: string;
40
+ lastName: string;
41
+ email: string;
42
+ phone: string;
43
+ title: string;
44
+ companyId: string;
45
+ createdAt: Date;
46
+ }[];
47
+ //#endregion
48
+ export { MOCK_COMPANIES, MOCK_CONTACTS, MOCK_DEALS, MOCK_STAGES, MockDeal, MockStage };
49
+ //# sourceMappingURL=mock-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-data.d.ts","names":[],"sources":["../../src/handlers/mock-data.ts"],"sourcesContent":[],"mappings":";;AAMA;;AAYa,UAZI,QAAA,CAYJ;EACA,EAAA,EAAA,MAAA;EAAI,IAAA,EAAA,MAAA;EAGA,KAAA,EAAA,MAAS;EASb,QAAA,EAAA,MAMZ;EAIY,UAAA,EAAA,MAyFZ;EAIY,OAAA,EAAA,MAAA;EAgCA,MAAA,EAAA,MAAA,GA+BZ,KAAA,GAAA,MAAA,GAAA,OAAA;;;;sBApLqB;aACT;aACA;;UAGI,SAAA;;;;;;cASJ,aAAa;cAUb,YAAY;cA6FZ;;;;;;;aA4BZ;;cAIY;;;;;;;;aA+BZ"}