@voyantjs/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 (60) hide show
  1. package/LICENSE +109 -0
  2. package/README.md +47 -0
  3. package/dist/booking-extension.d.ts +123 -0
  4. package/dist/booking-extension.d.ts.map +1 -0
  5. package/dist/booking-extension.js +86 -0
  6. package/dist/index.d.ts +14 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +29 -0
  9. package/dist/routes/accounts.d.ts +1203 -0
  10. package/dist/routes/accounts.d.ts.map +1 -0
  11. package/dist/routes/accounts.js +226 -0
  12. package/dist/routes/activities.d.ts +299 -0
  13. package/dist/routes/activities.d.ts.map +1 -0
  14. package/dist/routes/activities.js +61 -0
  15. package/dist/routes/custom-fields.d.ts +256 -0
  16. package/dist/routes/custom-fields.d.ts.map +1 -0
  17. package/dist/routes/custom-fields.js +46 -0
  18. package/dist/routes/index.d.ts +2671 -0
  19. package/dist/routes/index.d.ts.map +1 -0
  20. package/dist/routes/index.js +14 -0
  21. package/dist/routes/opportunities.d.ts +387 -0
  22. package/dist/routes/opportunities.d.ts.map +1 -0
  23. package/dist/routes/opportunities.js +69 -0
  24. package/dist/routes/pipelines.d.ts +292 -0
  25. package/dist/routes/pipelines.d.ts.map +1 -0
  26. package/dist/routes/pipelines.js +58 -0
  27. package/dist/routes/quotes.d.ts +283 -0
  28. package/dist/routes/quotes.d.ts.map +1 -0
  29. package/dist/routes/quotes.js +51 -0
  30. package/dist/schema.d.ts +3478 -0
  31. package/dist/schema.d.ts.map +1 -0
  32. package/dist/schema.js +515 -0
  33. package/dist/service/accounts.d.ts +982 -0
  34. package/dist/service/accounts.d.ts.map +1 -0
  35. package/dist/service/accounts.js +509 -0
  36. package/dist/service/activities.d.ts +486 -0
  37. package/dist/service/activities.d.ts.map +1 -0
  38. package/dist/service/activities.js +114 -0
  39. package/dist/service/custom-fields.d.ts +118 -0
  40. package/dist/service/custom-fields.d.ts.map +1 -0
  41. package/dist/service/custom-fields.js +88 -0
  42. package/dist/service/helpers.d.ts +22 -0
  43. package/dist/service/helpers.d.ts.map +1 -0
  44. package/dist/service/helpers.js +39 -0
  45. package/dist/service/index.d.ts +3329 -0
  46. package/dist/service/index.d.ts.map +1 -0
  47. package/dist/service/index.js +14 -0
  48. package/dist/service/opportunities.d.ts +822 -0
  49. package/dist/service/opportunities.d.ts.map +1 -0
  50. package/dist/service/opportunities.js +117 -0
  51. package/dist/service/pipelines.d.ts +113 -0
  52. package/dist/service/pipelines.d.ts.map +1 -0
  53. package/dist/service/pipelines.js +68 -0
  54. package/dist/service/quotes.d.ts +494 -0
  55. package/dist/service/quotes.d.ts.map +1 -0
  56. package/dist/service/quotes.js +69 -0
  57. package/dist/validation.d.ts +860 -0
  58. package/dist/validation.d.ts.map +1 -0
  59. package/dist/validation.js +315 -0
  60. package/package.json +56 -0
@@ -0,0 +1,118 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import type { z } from "zod";
3
+ import type { customFieldDefinitionListQuerySchema, customFieldValueListQuerySchema, insertCustomFieldDefinitionSchema, updateCustomFieldDefinitionSchema, upsertCustomFieldValueSchema } from "../validation.js";
4
+ type CustomFieldDefinitionListQuery = z.infer<typeof customFieldDefinitionListQuerySchema>;
5
+ type CreateCustomFieldDefinitionInput = z.infer<typeof insertCustomFieldDefinitionSchema>;
6
+ type UpdateCustomFieldDefinitionInput = z.infer<typeof updateCustomFieldDefinitionSchema>;
7
+ type CustomFieldValueListQuery = z.infer<typeof customFieldValueListQuerySchema>;
8
+ type UpsertCustomFieldValueInput = z.infer<typeof upsertCustomFieldValueSchema>;
9
+ export declare const customFieldsService: {
10
+ listCustomFieldDefinitions(db: PostgresJsDatabase, query: CustomFieldDefinitionListQuery): Promise<{
11
+ data: {
12
+ id: string;
13
+ entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
14
+ key: string;
15
+ label: string;
16
+ fieldType: "boolean" | "json" | "date" | "text" | "phone" | "set" | "enum" | "varchar" | "double" | "monetary" | "address";
17
+ isRequired: boolean;
18
+ isSearchable: boolean;
19
+ options: {
20
+ label: string;
21
+ value: string;
22
+ }[] | null;
23
+ createdAt: Date;
24
+ updatedAt: Date;
25
+ }[];
26
+ total: number;
27
+ limit: number;
28
+ offset: number;
29
+ }>;
30
+ getCustomFieldDefinitionById(db: PostgresJsDatabase, id: string): Promise<{
31
+ id: string;
32
+ entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
33
+ key: string;
34
+ label: string;
35
+ fieldType: "boolean" | "json" | "date" | "text" | "phone" | "set" | "enum" | "varchar" | "double" | "monetary" | "address";
36
+ isRequired: boolean;
37
+ isSearchable: boolean;
38
+ options: {
39
+ label: string;
40
+ value: string;
41
+ }[] | null;
42
+ createdAt: Date;
43
+ updatedAt: Date;
44
+ } | null>;
45
+ createCustomFieldDefinition(db: PostgresJsDatabase, data: CreateCustomFieldDefinitionInput): Promise<{
46
+ key: string;
47
+ createdAt: Date;
48
+ updatedAt: Date;
49
+ options: {
50
+ label: string;
51
+ value: string;
52
+ }[] | null;
53
+ entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
54
+ label: string;
55
+ id: string;
56
+ fieldType: "boolean" | "json" | "date" | "text" | "phone" | "set" | "enum" | "varchar" | "double" | "monetary" | "address";
57
+ isRequired: boolean;
58
+ isSearchable: boolean;
59
+ } | undefined>;
60
+ updateCustomFieldDefinition(db: PostgresJsDatabase, id: string, data: UpdateCustomFieldDefinitionInput): Promise<{
61
+ id: string;
62
+ entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
63
+ key: string;
64
+ label: string;
65
+ fieldType: "boolean" | "json" | "date" | "text" | "phone" | "set" | "enum" | "varchar" | "double" | "monetary" | "address";
66
+ isRequired: boolean;
67
+ isSearchable: boolean;
68
+ options: {
69
+ label: string;
70
+ value: string;
71
+ }[] | null;
72
+ createdAt: Date;
73
+ updatedAt: Date;
74
+ } | null>;
75
+ deleteCustomFieldDefinition(db: PostgresJsDatabase, id: string): Promise<{
76
+ id: string;
77
+ } | null>;
78
+ listCustomFieldValues(db: PostgresJsDatabase, query: CustomFieldValueListQuery): Promise<{
79
+ data: {
80
+ id: string;
81
+ definitionId: string;
82
+ entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
83
+ entityId: string;
84
+ textValue: string | null;
85
+ numberValue: number | null;
86
+ dateValue: string | null;
87
+ booleanValue: boolean | null;
88
+ monetaryValueCents: number | null;
89
+ currencyCode: string | null;
90
+ jsonValue: Record<string, unknown> | string[] | null;
91
+ createdAt: Date;
92
+ updatedAt: Date;
93
+ }[];
94
+ total: number;
95
+ limit: number;
96
+ offset: number;
97
+ }>;
98
+ upsertCustomFieldValue(db: PostgresJsDatabase, definitionId: string, data: UpsertCustomFieldValueInput): Promise<{
99
+ createdAt: Date;
100
+ updatedAt: Date;
101
+ entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
102
+ entityId: string;
103
+ id: string;
104
+ definitionId: string;
105
+ textValue: string | null;
106
+ numberValue: number | null;
107
+ dateValue: string | null;
108
+ booleanValue: boolean | null;
109
+ monetaryValueCents: number | null;
110
+ currencyCode: string | null;
111
+ jsonValue: Record<string, unknown> | string[] | null;
112
+ } | undefined>;
113
+ deleteCustomFieldValue(db: PostgresJsDatabase, id: string): Promise<{
114
+ id: string;
115
+ } | null>;
116
+ };
117
+ export {};
118
+ //# sourceMappingURL=custom-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-fields.d.ts","sourceRoot":"","sources":["../../src/service/custom-fields.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAG5B,OAAO,KAAK,EACV,oCAAoC,EACpC,+BAA+B,EAC/B,iCAAiC,EACjC,iCAAiC,EACjC,4BAA4B,EAC7B,MAAM,kBAAkB,CAAA;AAGzB,KAAK,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAA;AAC1F,KAAK,gCAAgC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAA;AACzF,KAAK,gCAAgC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAA;AACzF,KAAK,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAA;AAChF,KAAK,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AAE/E,eAAO,MAAM,mBAAmB;mCACO,kBAAkB,SAAS,8BAA8B;;;;;;;;;;;;;;;;;;;;qCAkBvD,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;;oCAU/D,kBAAkB,QAChB,gCAAgC;;;;;;;;;;;;;;;oCAOlC,kBAAkB,MAClB,MAAM,QACJ,gCAAgC;;;;;;;;;;;;;;;oCAUF,kBAAkB,MAAM,MAAM;;;8BAQpC,kBAAkB,SAAS,yBAAyB;;;;;;;;;;;;;;;;;;;;+BAsB9E,kBAAkB,gBACR,MAAM,QACd,2BAA2B;;;;;;;;;;;;;;;+BA8BF,kBAAkB,MAAM,MAAM;;;CAOhE,CAAA"}
@@ -0,0 +1,88 @@
1
+ import { and, desc, eq, sql } from "drizzle-orm";
2
+ import { customFieldDefinitions, customFieldValues } from "../schema.js";
3
+ import { paginate } from "./helpers.js";
4
+ export const customFieldsService = {
5
+ async listCustomFieldDefinitions(db, query) {
6
+ const where = query.entityType
7
+ ? eq(customFieldDefinitions.entityType, query.entityType)
8
+ : undefined;
9
+ return paginate(db
10
+ .select()
11
+ .from(customFieldDefinitions)
12
+ .where(where)
13
+ .limit(query.limit)
14
+ .offset(query.offset)
15
+ .orderBy(customFieldDefinitions.entityType, customFieldDefinitions.label), db.select({ count: sql `count(*)::int` }).from(customFieldDefinitions).where(where), query.limit, query.offset);
16
+ },
17
+ async getCustomFieldDefinitionById(db, id) {
18
+ const [row] = await db
19
+ .select()
20
+ .from(customFieldDefinitions)
21
+ .where(eq(customFieldDefinitions.id, id))
22
+ .limit(1);
23
+ return row ?? null;
24
+ },
25
+ async createCustomFieldDefinition(db, data) {
26
+ const [row] = await db.insert(customFieldDefinitions).values(data).returning();
27
+ return row;
28
+ },
29
+ async updateCustomFieldDefinition(db, id, data) {
30
+ const [row] = await db
31
+ .update(customFieldDefinitions)
32
+ .set({ ...data, updatedAt: new Date() })
33
+ .where(eq(customFieldDefinitions.id, id))
34
+ .returning();
35
+ return row ?? null;
36
+ },
37
+ async deleteCustomFieldDefinition(db, id) {
38
+ const [row] = await db
39
+ .delete(customFieldDefinitions)
40
+ .where(eq(customFieldDefinitions.id, id))
41
+ .returning({ id: customFieldDefinitions.id });
42
+ return row ?? null;
43
+ },
44
+ async listCustomFieldValues(db, query) {
45
+ const conditions = [];
46
+ if (query.entityType)
47
+ conditions.push(eq(customFieldValues.entityType, query.entityType));
48
+ if (query.entityId)
49
+ conditions.push(eq(customFieldValues.entityId, query.entityId));
50
+ if (query.definitionId)
51
+ conditions.push(eq(customFieldValues.definitionId, query.definitionId));
52
+ const where = conditions.length ? and(...conditions) : undefined;
53
+ return paginate(db
54
+ .select()
55
+ .from(customFieldValues)
56
+ .where(where)
57
+ .limit(query.limit)
58
+ .offset(query.offset)
59
+ .orderBy(desc(customFieldValues.updatedAt)), db.select({ count: sql `count(*)::int` }).from(customFieldValues).where(where), query.limit, query.offset);
60
+ },
61
+ async upsertCustomFieldValue(db, definitionId, data) {
62
+ const [existing] = await db
63
+ .select()
64
+ .from(customFieldValues)
65
+ .where(and(eq(customFieldValues.definitionId, definitionId), eq(customFieldValues.entityType, data.entityType), eq(customFieldValues.entityId, data.entityId)))
66
+ .limit(1);
67
+ if (existing) {
68
+ const [row] = await db
69
+ .update(customFieldValues)
70
+ .set({ ...data, definitionId, updatedAt: new Date() })
71
+ .where(eq(customFieldValues.id, existing.id))
72
+ .returning();
73
+ return row;
74
+ }
75
+ const [row] = await db
76
+ .insert(customFieldValues)
77
+ .values({ ...data, definitionId })
78
+ .returning();
79
+ return row;
80
+ },
81
+ async deleteCustomFieldValue(db, id) {
82
+ const [row] = await db
83
+ .delete(customFieldValues)
84
+ .where(eq(customFieldValues.id, id))
85
+ .returning({ id: customFieldValues.id });
86
+ return row ?? null;
87
+ },
88
+ };
@@ -0,0 +1,22 @@
1
+ export declare function paginate<T extends object>(rowsQuery: Promise<T[]>, countQuery: Promise<Array<{
2
+ count: number;
3
+ }>>, limit: number, offset: number): Promise<{
4
+ data: T[];
5
+ total: number;
6
+ limit: number;
7
+ offset: number;
8
+ }>;
9
+ export declare function toDateOrNull(value: string | null | undefined): Date | null;
10
+ export declare function normalizeContactValue(kind: "email" | "phone" | "website", value: string): string;
11
+ export declare function isManagedBySource(metadata: Record<string, unknown> | null | undefined, source: string): boolean;
12
+ export declare function toNullableTrimmed(value: string | null | undefined): string | null;
13
+ export declare function formatAddress(address: {
14
+ fullText: string | null;
15
+ line1: string | null;
16
+ line2: string | null;
17
+ city: string | null;
18
+ region: string | null;
19
+ postalCode: string | null;
20
+ country: string | null;
21
+ }): string | null;
22
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/service/helpers.ts"],"names":[],"mappings":"AAAA,wBAAsB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAC7C,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EACvB,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,EAC7C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM;;;;;GAUf;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,eAE5D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,UAKvF;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EACpD,MAAM,EAAE,MAAM,WAGf;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,iBAGjE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACrC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,iBAaA"}
@@ -0,0 +1,39 @@
1
+ export async function paginate(rowsQuery, countQuery, limit, offset) {
2
+ const [data, countResult] = await Promise.all([rowsQuery, countQuery]);
3
+ return {
4
+ data,
5
+ total: countResult[0]?.count ?? 0,
6
+ limit,
7
+ offset,
8
+ };
9
+ }
10
+ export function toDateOrNull(value) {
11
+ return value ? new Date(value) : null;
12
+ }
13
+ export function normalizeContactValue(kind, value) {
14
+ if (kind === "email" || kind === "website") {
15
+ return value.trim().toLowerCase();
16
+ }
17
+ return value.trim();
18
+ }
19
+ export function isManagedBySource(metadata, source) {
20
+ return metadata?.managedBy === source;
21
+ }
22
+ export function toNullableTrimmed(value) {
23
+ const trimmed = value?.trim();
24
+ return trimmed ? trimmed : null;
25
+ }
26
+ export function formatAddress(address) {
27
+ if (address.fullText) {
28
+ return address.fullText;
29
+ }
30
+ const parts = [
31
+ address.line1,
32
+ address.line2,
33
+ address.city,
34
+ address.region,
35
+ address.postalCode,
36
+ address.country,
37
+ ].filter(Boolean);
38
+ return parts.length > 0 ? parts.join(", ") : null;
39
+ }