@clivly/core 0.1.0 → 0.2.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.
@@ -0,0 +1,161 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_view_compiler = require("./view-compiler.cjs");
3
+ //#region src/sync-engine.ts
4
+ /**
5
+ * Diff a view's rows against the current mirror population for one entity.
6
+ *
7
+ * - source row with no mirror row → create
8
+ * - source row with a live mirror row → update (overwrite identity fields)
9
+ * - source row with an archived mirror → restore (re-activate + update)
10
+ * - live mirror row absent from source → archive (soft delete, keep history)
11
+ * - archived mirror row absent from source → no-op
12
+ *
13
+ * Source rows are de-duplicated by the reconciliation key (first wins). In
14
+ * simple mode (default) the key is `sourceRef`. In composite mode — used for
15
+ * `through` (join-table) entities, where the compiled view fans a person out
16
+ * into one row per membership — the key is `(sourceRef, companyRef)`, so a
17
+ * person in several companies materializes one mirror row per company and a
18
+ * single membership leaving archives only that one row.
19
+ */
20
+ function reconcile(source, mirror, opts = {}) {
21
+ const keyOf = (sourceRef, companyRef) => opts.composite ? `${sourceRef}\0${companyRef ?? ""}` : sourceRef;
22
+ const seen = /* @__PURE__ */ new Set();
23
+ const rows = [];
24
+ for (const row of source) {
25
+ const key = keyOf(row.sourceRef, row.companyRef ?? null);
26
+ if (!seen.has(key)) {
27
+ seen.add(key);
28
+ rows.push(row);
29
+ }
30
+ }
31
+ const byKey = new Map(mirror.map((m) => [keyOf(m.sourceRef, m.companyRef), m]));
32
+ const liveKeys = /* @__PURE__ */ new Set();
33
+ const actions = [];
34
+ for (const row of rows) {
35
+ const companyRef = row.companyRef ?? null;
36
+ const key = keyOf(row.sourceRef, companyRef);
37
+ liveKeys.add(key);
38
+ const existing = byKey.get(key);
39
+ if (!existing) actions.push({
40
+ kind: "create",
41
+ sourceRef: row.sourceRef,
42
+ fields: row.fields,
43
+ companyRef
44
+ });
45
+ else if (existing.archivedAt) actions.push({
46
+ kind: "restore",
47
+ id: existing.id,
48
+ sourceRef: row.sourceRef,
49
+ fields: row.fields,
50
+ companyRef
51
+ });
52
+ else actions.push({
53
+ kind: "update",
54
+ id: existing.id,
55
+ sourceRef: row.sourceRef,
56
+ fields: row.fields,
57
+ companyRef
58
+ });
59
+ }
60
+ for (const m of mirror) {
61
+ const key = keyOf(m.sourceRef, m.companyRef);
62
+ if (!(liveKeys.has(key) || m.archivedAt)) actions.push({
63
+ kind: "archive",
64
+ id: m.id,
65
+ sourceRef: m.sourceRef
66
+ });
67
+ }
68
+ return actions;
69
+ }
70
+ const CONCEPT_ORDER = {
71
+ company: 0,
72
+ contact: 1
73
+ };
74
+ /** Companies before contacts, so contact company_refs resolve to a live mirror. */
75
+ function syncOrder(a, b) {
76
+ return (CONCEPT_ORDER[a.concept] ?? 99) - (CONCEPT_ORDER[b.concept] ?? 99);
77
+ }
78
+ async function resolveActions(store, actions) {
79
+ const refs = /* @__PURE__ */ new Set();
80
+ for (const action of actions) if (action.kind !== "archive" && action.companyRef) refs.add(action.companyRef);
81
+ const resolved = refs.size ? await store.resolveCompanyRefs([...refs]) : /* @__PURE__ */ new Map();
82
+ return actions.map((action) => {
83
+ if (action.kind === "archive") return action;
84
+ const companyId = action.companyRef ? resolved.get(action.companyRef) ?? null : null;
85
+ return {
86
+ kind: action.kind,
87
+ id: "id" in action ? action.id : "",
88
+ sourceRef: action.sourceRef,
89
+ fields: action.fields,
90
+ companyId,
91
+ companySourceRef: action.companyRef ?? null
92
+ };
93
+ });
94
+ }
95
+ function emptyTally() {
96
+ return {
97
+ create: 0,
98
+ update: 0,
99
+ restore: 0,
100
+ archive: 0
101
+ };
102
+ }
103
+ /**
104
+ * An entity whose company relationship is a `through` (join-table) join fans out
105
+ * into one source row per membership, so its mirror must be keyed compositely.
106
+ */
107
+ function isCompositeEntity(config, entityKey) {
108
+ const entity = config.entities[entityKey];
109
+ if (!entity?.relationships) return false;
110
+ return Object.values(entity.relationships).some((rel) => "through" in rel.via);
111
+ }
112
+ /**
113
+ * Run a full sync: compile the config's views, then reconcile + persist each,
114
+ * companies first. Returns per-entity and total action counts.
115
+ */
116
+ async function runSync(config, store, options = {}) {
117
+ const views = require_view_compiler.compileEntityViews(config, options).sort(syncOrder);
118
+ const entities = [];
119
+ const totals = {
120
+ created: 0,
121
+ updated: 0,
122
+ restored: 0,
123
+ archived: 0
124
+ };
125
+ for (const view of views) {
126
+ const [source, mirror] = await Promise.all([store.readView(view), store.listMirror({
127
+ concept: view.concept,
128
+ role: view.role
129
+ })]);
130
+ const actions = reconcile(source, mirror, { composite: isCompositeEntity(config, view.entityKey) });
131
+ const persistActions = await resolveActions(store, actions);
132
+ await store.persist({
133
+ concept: view.concept,
134
+ role: view.role,
135
+ actions: persistActions
136
+ });
137
+ const counts = emptyTally();
138
+ for (const action of actions) counts[action.kind] += 1;
139
+ const result = {
140
+ entityKey: view.entityKey,
141
+ concept: view.concept,
142
+ role: view.role,
143
+ created: counts.create,
144
+ updated: counts.update,
145
+ restored: counts.restore,
146
+ archived: counts.archive
147
+ };
148
+ entities.push(result);
149
+ totals.created += result.created;
150
+ totals.updated += result.updated;
151
+ totals.restored += result.restored;
152
+ totals.archived += result.archived;
153
+ }
154
+ return {
155
+ entities,
156
+ totals
157
+ };
158
+ }
159
+ //#endregion
160
+ exports.reconcile = reconcile;
161
+ exports.runSync = runSync;
@@ -0,0 +1,148 @@
1
+ import { ClivlyEntitiesConfig } from "./entity-config.cjs";
2
+ import { CompileOptions, CompiledView } from "./view-compiler.cjs";
3
+
4
+ //#region src/sync-engine.d.ts
5
+ /**
6
+ * Sync engine (Phase 3) — materializes the read-only entity views into Clivly's
7
+ * own mirror tables (`crm_companies`, `crm_contacts`).
8
+ *
9
+ * The reconciliation is the heart of the design: rows present in a view are
10
+ * created or updated in the mirror; rows that *leave* a view (e.g. an owner
11
+ * demoted to a member) are **archived, not deleted**, so their deals/activities
12
+ * survive. Identity fields are host-owned and overwritten each run; Clivly-owned
13
+ * CRM fields are never touched here.
14
+ *
15
+ * `reconcile()` is a pure function and independently testable. `runSync()`
16
+ * orchestrates: compile views → for each (companies first, so contact
17
+ * `company_ref`s resolve to a live `crm_companies.id`) read the view, reconcile
18
+ * against the current mirror, resolve company refs, and persist. All DB I/O is
19
+ * behind the `SyncStore` port — core stays ORM-agnostic; the SDK/drizzle
20
+ * package provides the concrete store.
21
+ */
22
+ /** A row read from a compiled view (what Postgres returns). */
23
+ interface SourceRow {
24
+ /** Host-side company key from `<relationship>_ref`; resolved before persist. */
25
+ companyRef?: string | null;
26
+ /** Mapped identity fields (clivly field → value). */
27
+ fields: Record<string, string | null>;
28
+ /** The source primary key — becomes the mirror row's `source_ref`. */
29
+ sourceRef: string;
30
+ }
31
+ /** An existing mirror row, as far as reconciliation needs to know. */
32
+ interface MirrorRecord {
33
+ archivedAt: Date | null;
34
+ /** Host-side company key; only consulted in composite (join-table) mode. */
35
+ companyRef: string | null;
36
+ id: string;
37
+ sourceRef: string;
38
+ }
39
+ type SyncAction = {
40
+ kind: "create";
41
+ sourceRef: string;
42
+ fields: Record<string, string | null>;
43
+ companyRef: string | null;
44
+ } | {
45
+ kind: "update";
46
+ id: string;
47
+ sourceRef: string;
48
+ fields: Record<string, string | null>;
49
+ companyRef: string | null;
50
+ } | {
51
+ kind: "restore";
52
+ id: string;
53
+ sourceRef: string;
54
+ fields: Record<string, string | null>;
55
+ companyRef: string | null;
56
+ } | {
57
+ kind: "archive";
58
+ id: string;
59
+ sourceRef: string;
60
+ };
61
+ /** A persist action with the company ref resolved to a `crm_companies.id`. */
62
+ type PersistAction = {
63
+ kind: "create";
64
+ sourceRef: string;
65
+ fields: Record<string, string | null>;
66
+ companyId: string | null;
67
+ companySourceRef: string | null;
68
+ } | {
69
+ kind: "update";
70
+ id: string;
71
+ sourceRef: string;
72
+ fields: Record<string, string | null>;
73
+ companyId: string | null;
74
+ companySourceRef: string | null;
75
+ } | {
76
+ kind: "restore";
77
+ id: string;
78
+ sourceRef: string;
79
+ fields: Record<string, string | null>;
80
+ companyId: string | null;
81
+ companySourceRef: string | null;
82
+ } | {
83
+ kind: "archive";
84
+ id: string;
85
+ sourceRef: string;
86
+ };
87
+ /**
88
+ * Diff a view's rows against the current mirror population for one entity.
89
+ *
90
+ * - source row with no mirror row → create
91
+ * - source row with a live mirror row → update (overwrite identity fields)
92
+ * - source row with an archived mirror → restore (re-activate + update)
93
+ * - live mirror row absent from source → archive (soft delete, keep history)
94
+ * - archived mirror row absent from source → no-op
95
+ *
96
+ * Source rows are de-duplicated by the reconciliation key (first wins). In
97
+ * simple mode (default) the key is `sourceRef`. In composite mode — used for
98
+ * `through` (join-table) entities, where the compiled view fans a person out
99
+ * into one row per membership — the key is `(sourceRef, companyRef)`, so a
100
+ * person in several companies materializes one mirror row per company and a
101
+ * single membership leaving archives only that one row.
102
+ */
103
+ declare function reconcile(source: SourceRow[], mirror: MirrorRecord[], opts?: {
104
+ composite?: boolean;
105
+ }): SyncAction[];
106
+ /** DB I/O port. The concrete store lives in the SDK/drizzle package. */
107
+ interface SyncStore {
108
+ /** Current mirror rows for a concept + role (including archived). */
109
+ listMirror(input: {
110
+ concept: string;
111
+ role: string;
112
+ }): Promise<MirrorRecord[]>;
113
+ /** Apply the resolved actions to the mirror table for this concept + role. */
114
+ persist(input: {
115
+ concept: string;
116
+ role: string;
117
+ actions: PersistAction[];
118
+ }): Promise<void>;
119
+ /** Execute the view's SQL and return its rows. */
120
+ readView(view: CompiledView): Promise<SourceRow[]>;
121
+ /** Map host-side company refs → `crm_companies.id` (already-synced companies only). */
122
+ resolveCompanyRefs(refs: string[]): Promise<Map<string, string>>;
123
+ }
124
+ interface EntitySyncResult {
125
+ archived: number;
126
+ concept: string;
127
+ created: number;
128
+ entityKey: string;
129
+ restored: number;
130
+ role: string;
131
+ updated: number;
132
+ }
133
+ interface SyncResult {
134
+ entities: EntitySyncResult[];
135
+ totals: {
136
+ created: number;
137
+ updated: number;
138
+ restored: number;
139
+ archived: number;
140
+ };
141
+ }
142
+ /**
143
+ * Run a full sync: compile the config's views, then reconcile + persist each,
144
+ * companies first. Returns per-entity and total action counts.
145
+ */
146
+ declare function runSync(config: ClivlyEntitiesConfig, store: SyncStore, options?: CompileOptions): Promise<SyncResult>;
147
+ //#endregion
148
+ export { EntitySyncResult, MirrorRecord, PersistAction, SourceRow, SyncAction, SyncResult, SyncStore, reconcile, runSync };
@@ -31,6 +31,8 @@ interface SourceRow {
31
31
  /** An existing mirror row, as far as reconciliation needs to know. */
32
32
  interface MirrorRecord {
33
33
  archivedAt: Date | null;
34
+ /** Host-side company key; only consulted in composite (join-table) mode. */
35
+ companyRef: string | null;
34
36
  id: string;
35
37
  sourceRef: string;
36
38
  }
@@ -62,18 +64,21 @@ type PersistAction = {
62
64
  sourceRef: string;
63
65
  fields: Record<string, string | null>;
64
66
  companyId: string | null;
67
+ companySourceRef: string | null;
65
68
  } | {
66
69
  kind: "update";
67
70
  id: string;
68
71
  sourceRef: string;
69
72
  fields: Record<string, string | null>;
70
73
  companyId: string | null;
74
+ companySourceRef: string | null;
71
75
  } | {
72
76
  kind: "restore";
73
77
  id: string;
74
78
  sourceRef: string;
75
79
  fields: Record<string, string | null>;
76
80
  companyId: string | null;
81
+ companySourceRef: string | null;
77
82
  } | {
78
83
  kind: "archive";
79
84
  id: string;
@@ -88,11 +93,16 @@ type PersistAction = {
88
93
  * - live mirror row absent from source → archive (soft delete, keep history)
89
94
  * - archived mirror row absent from source → no-op
90
95
  *
91
- * Source rows are de-duplicated by `sourceRef` (first wins). A person appearing
92
- * under multiple companies (many-to-many via a join table) collapses to their
93
- * first company here; richer many-to-many membership is deferred.
96
+ * Source rows are de-duplicated by the reconciliation key (first wins). In
97
+ * simple mode (default) the key is `sourceRef`. In composite mode — used for
98
+ * `through` (join-table) entities, where the compiled view fans a person out
99
+ * into one row per membership — the key is `(sourceRef, companyRef)`, so a
100
+ * person in several companies materializes one mirror row per company and a
101
+ * single membership leaving archives only that one row.
94
102
  */
95
- declare function reconcile(source: SourceRow[], mirror: MirrorRecord[]): SyncAction[];
103
+ declare function reconcile(source: SourceRow[], mirror: MirrorRecord[], opts?: {
104
+ composite?: boolean;
105
+ }): SyncAction[];
96
106
  /** DB I/O port. The concrete store lives in the SDK/drizzle package. */
97
107
  interface SyncStore {
98
108
  /** Current mirror rows for a concept + role (including archived). */
@@ -9,24 +9,32 @@ import { compileEntityViews } from "./view-compiler.mjs";
9
9
  * - live mirror row absent from source → archive (soft delete, keep history)
10
10
  * - archived mirror row absent from source → no-op
11
11
  *
12
- * Source rows are de-duplicated by `sourceRef` (first wins). A person appearing
13
- * under multiple companies (many-to-many via a join table) collapses to their
14
- * first company here; richer many-to-many membership is deferred.
12
+ * Source rows are de-duplicated by the reconciliation key (first wins). In
13
+ * simple mode (default) the key is `sourceRef`. In composite mode — used for
14
+ * `through` (join-table) entities, where the compiled view fans a person out
15
+ * into one row per membership — the key is `(sourceRef, companyRef)`, so a
16
+ * person in several companies materializes one mirror row per company and a
17
+ * single membership leaving archives only that one row.
15
18
  */
16
- function reconcile(source, mirror) {
19
+ function reconcile(source, mirror, opts = {}) {
20
+ const keyOf = (sourceRef, companyRef) => opts.composite ? `${sourceRef}\0${companyRef ?? ""}` : sourceRef;
17
21
  const seen = /* @__PURE__ */ new Set();
18
22
  const rows = [];
19
- for (const row of source) if (!seen.has(row.sourceRef)) {
20
- seen.add(row.sourceRef);
21
- rows.push(row);
23
+ for (const row of source) {
24
+ const key = keyOf(row.sourceRef, row.companyRef ?? null);
25
+ if (!seen.has(key)) {
26
+ seen.add(key);
27
+ rows.push(row);
28
+ }
22
29
  }
23
- const byRef = new Map(mirror.map((m) => [m.sourceRef, m]));
24
- const liveRefs = /* @__PURE__ */ new Set();
30
+ const byKey = new Map(mirror.map((m) => [keyOf(m.sourceRef, m.companyRef), m]));
31
+ const liveKeys = /* @__PURE__ */ new Set();
25
32
  const actions = [];
26
33
  for (const row of rows) {
27
- liveRefs.add(row.sourceRef);
28
- const existing = byRef.get(row.sourceRef);
29
34
  const companyRef = row.companyRef ?? null;
35
+ const key = keyOf(row.sourceRef, companyRef);
36
+ liveKeys.add(key);
37
+ const existing = byKey.get(key);
30
38
  if (!existing) actions.push({
31
39
  kind: "create",
32
40
  sourceRef: row.sourceRef,
@@ -48,11 +56,14 @@ function reconcile(source, mirror) {
48
56
  companyRef
49
57
  });
50
58
  }
51
- for (const m of mirror) if (!(liveRefs.has(m.sourceRef) || m.archivedAt)) actions.push({
52
- kind: "archive",
53
- id: m.id,
54
- sourceRef: m.sourceRef
55
- });
59
+ for (const m of mirror) {
60
+ const key = keyOf(m.sourceRef, m.companyRef);
61
+ if (!(liveKeys.has(key) || m.archivedAt)) actions.push({
62
+ kind: "archive",
63
+ id: m.id,
64
+ sourceRef: m.sourceRef
65
+ });
66
+ }
56
67
  return actions;
57
68
  }
58
69
  const CONCEPT_ORDER = {
@@ -75,7 +86,8 @@ async function resolveActions(store, actions) {
75
86
  id: "id" in action ? action.id : "",
76
87
  sourceRef: action.sourceRef,
77
88
  fields: action.fields,
78
- companyId
89
+ companyId,
90
+ companySourceRef: action.companyRef ?? null
79
91
  };
80
92
  });
81
93
  }
@@ -88,6 +100,15 @@ function emptyTally() {
88
100
  };
89
101
  }
90
102
  /**
103
+ * An entity whose company relationship is a `through` (join-table) join fans out
104
+ * into one source row per membership, so its mirror must be keyed compositely.
105
+ */
106
+ function isCompositeEntity(config, entityKey) {
107
+ const entity = config.entities[entityKey];
108
+ if (!entity?.relationships) return false;
109
+ return Object.values(entity.relationships).some((rel) => "through" in rel.via);
110
+ }
111
+ /**
91
112
  * Run a full sync: compile the config's views, then reconcile + persist each,
92
113
  * companies first. Returns per-entity and total action counts.
93
114
  */
@@ -105,7 +126,7 @@ async function runSync(config, store, options = {}) {
105
126
  concept: view.concept,
106
127
  role: view.role
107
128
  })]);
108
- const actions = reconcile(source, mirror);
129
+ const actions = reconcile(source, mirror, { composite: isCompositeEntity(config, view.entityKey) });
109
130
  const persistActions = await resolveActions(store, actions);
110
131
  await store.persist({
111
132
  concept: view.concept,
package/dist/types.cjs ADDED
File without changes
@@ -0,0 +1,156 @@
1
+ //#region src/types.d.ts
2
+ type ContactStatus = "lead" | "active" | "customer" | "churned";
3
+ type DealStage = "lead" | "qualified" | "proposal" | "negotiation" | "won" | "lost";
4
+ type TaskStatus = "todo" | "in_progress" | "done" | "cancelled";
5
+ type TaskPriority = "low" | "medium" | "high";
6
+ type TaskEntityType = "contact" | "company" | "deal";
7
+ type ActivityType = "note" | "email" | "task" | "deal" | "call";
8
+ type CrmRole = "owner" | "admin" | "member" | "developer" | "support_agent";
9
+ interface Contact {
10
+ companyId: string | null;
11
+ createdAt: Date;
12
+ email: string;
13
+ id: string;
14
+ lastActivityAt: Date | null;
15
+ name: string;
16
+ orgId: string;
17
+ status: ContactStatus;
18
+ title: string | null;
19
+ }
20
+ interface Company {
21
+ createdAt: Date;
22
+ domain: string | null;
23
+ id: string;
24
+ industry: string | null;
25
+ name: string;
26
+ orgId: string;
27
+ size: string | null;
28
+ }
29
+ interface Deal {
30
+ closeDate: Date | null;
31
+ contactId: string | null;
32
+ createdAt: Date;
33
+ id: string;
34
+ name: string;
35
+ orgId: string;
36
+ owner: string | null;
37
+ stage: DealStage;
38
+ value: number;
39
+ }
40
+ interface Task {
41
+ archivedAt: Date | null;
42
+ assignee: string | null;
43
+ completedAt: Date | null;
44
+ contactId: string | null;
45
+ createdAt: Date;
46
+ createdBy: string | null;
47
+ description: string | null;
48
+ dueAt: Date | null;
49
+ entityId: string | null;
50
+ entityType: TaskEntityType | null;
51
+ id: string;
52
+ orgId: string;
53
+ priority: TaskPriority;
54
+ status: TaskStatus;
55
+ title: string;
56
+ }
57
+ interface Note {
58
+ archivedAt: Date | null;
59
+ author: string | null;
60
+ body: string;
61
+ contactId: string | null;
62
+ createdAt: Date;
63
+ createdBy: string | null;
64
+ entityId: string | null;
65
+ entityType: TaskEntityType | null;
66
+ id: string;
67
+ isTemplate: boolean;
68
+ orgId: string;
69
+ title: string;
70
+ updatedAt: Date;
71
+ }
72
+ interface Activity {
73
+ actor: string | null;
74
+ contactId: string | null;
75
+ createdAt: Date;
76
+ id: string;
77
+ orgId: string;
78
+ summary: string;
79
+ type: ActivityType;
80
+ }
81
+ interface CreateContactInput {
82
+ companyId?: string;
83
+ email: string;
84
+ name: string;
85
+ status?: ContactStatus;
86
+ title?: string;
87
+ }
88
+ interface UpdateContactInput {
89
+ companyId?: string | null;
90
+ email?: string;
91
+ name?: string;
92
+ status?: ContactStatus;
93
+ title?: string | null;
94
+ }
95
+ interface CreateCompanyInput {
96
+ domain?: string;
97
+ industry?: string;
98
+ name: string;
99
+ size?: string;
100
+ }
101
+ interface CreateDealInput {
102
+ contactId?: string;
103
+ name: string;
104
+ owner?: string;
105
+ stage?: DealStage;
106
+ value?: number;
107
+ }
108
+ interface UpdateDealInput {
109
+ closeDate?: Date | null;
110
+ contactId?: string | null;
111
+ name?: string;
112
+ owner?: string | null;
113
+ stage?: DealStage;
114
+ value?: number;
115
+ }
116
+ interface CreateTaskInput {
117
+ assignee?: string;
118
+ createdBy?: string;
119
+ description?: string;
120
+ dueAt?: Date;
121
+ entityId?: string;
122
+ entityType?: TaskEntityType;
123
+ priority?: TaskPriority;
124
+ title: string;
125
+ }
126
+ interface UpdateTaskInput {
127
+ assignee?: string | null;
128
+ description?: string | null;
129
+ dueAt?: Date | null;
130
+ entityId?: string | null;
131
+ entityType?: TaskEntityType | null;
132
+ priority?: TaskPriority;
133
+ title?: string;
134
+ }
135
+ interface CreateActivityInput {
136
+ actor?: string;
137
+ contactId?: string;
138
+ summary: string;
139
+ type: ActivityType;
140
+ }
141
+ interface ContactFilters {
142
+ companyId?: string;
143
+ search?: string;
144
+ status?: ContactStatus;
145
+ }
146
+ interface TaskFilters {
147
+ assignee?: string;
148
+ entityId?: string;
149
+ entityType?: TaskEntityType;
150
+ includeArchived?: boolean;
151
+ includeCompleted?: boolean;
152
+ priority?: TaskPriority;
153
+ status?: TaskStatus;
154
+ }
155
+ //#endregion
156
+ export { Activity, ActivityType, Company, Contact, ContactFilters, ContactStatus, CreateActivityInput, CreateCompanyInput, CreateContactInput, CreateDealInput, CreateTaskInput, CrmRole, Deal, DealStage, Note, Task, TaskEntityType, TaskFilters, TaskPriority, TaskStatus, UpdateContactInput, UpdateDealInput, UpdateTaskInput };
package/dist/types.d.mts CHANGED
@@ -105,6 +105,14 @@ interface CreateDealInput {
105
105
  stage?: DealStage;
106
106
  value?: number;
107
107
  }
108
+ interface UpdateDealInput {
109
+ closeDate?: Date | null;
110
+ contactId?: string | null;
111
+ name?: string;
112
+ owner?: string | null;
113
+ stage?: DealStage;
114
+ value?: number;
115
+ }
108
116
  interface CreateTaskInput {
109
117
  assignee?: string;
110
118
  createdBy?: string;
@@ -145,4 +153,4 @@ interface TaskFilters {
145
153
  status?: TaskStatus;
146
154
  }
147
155
  //#endregion
148
- export { Activity, ActivityType, Company, Contact, ContactFilters, ContactStatus, CreateActivityInput, CreateCompanyInput, CreateContactInput, CreateDealInput, CreateTaskInput, CrmRole, Deal, DealStage, Note, Task, TaskEntityType, TaskFilters, TaskPriority, TaskStatus, UpdateContactInput, UpdateTaskInput };
156
+ export { Activity, ActivityType, Company, Contact, ContactFilters, ContactStatus, CreateActivityInput, CreateCompanyInput, CreateContactInput, CreateDealInput, CreateTaskInput, CrmRole, Deal, DealStage, Note, Task, TaskEntityType, TaskFilters, TaskPriority, TaskStatus, UpdateContactInput, UpdateDealInput, UpdateTaskInput };