clivly 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -3
- package/adapter-Cd6D_3JD.d.mts +46 -0
- package/adapter-Cy4q2CLs.d.cts +46 -0
- package/auth-adapter-CBOKDhlc.cjs +11 -0
- package/auth-adapter-CRBW4elj.d.mts +30 -0
- package/auth-adapter-CdLODn2p.d.cts +30 -0
- package/auth-adapter-wqnnEjo3.mjs +6 -0
- package/auth-better-auth.cjs +28 -0
- package/auth-better-auth.d.cts +33 -0
- package/auth-better-auth.d.mts +33 -0
- package/auth-better-auth.mjs +26 -0
- package/auth-clerk.cjs +34 -0
- package/auth-clerk.d.cts +32 -0
- package/auth-clerk.d.mts +32 -0
- package/auth-clerk.mjs +32 -0
- package/auth-workos.cjs +47 -0
- package/auth-workos.d.cts +30 -0
- package/auth-workos.d.mts +30 -0
- package/auth-workos.mjs +45 -0
- package/core-adapter.cjs +0 -0
- package/core-adapter.d.cts +2 -0
- package/core-adapter.d.mts +2 -0
- package/core-adapter.mjs +1 -0
- package/core-auth-adapter.cjs +3 -0
- package/core-auth-adapter.d.cts +2 -0
- package/core-auth-adapter.d.mts +2 -0
- package/core-auth-adapter.mjs +2 -0
- package/core-drizzle.cjs +32 -0
- package/core-drizzle.d.cts +21 -0
- package/core-drizzle.d.mts +21 -0
- package/core-drizzle.mjs +31 -0
- package/core-entity-config.cjs +13 -0
- package/core-entity-config.d.cts +2 -0
- package/core-entity-config.d.mts +2 -0
- package/core-entity-config.mjs +2 -0
- package/core-entity-heuristics.cjs +442 -0
- package/core-entity-heuristics.d.cts +68 -0
- package/core-entity-heuristics.d.mts +68 -0
- package/core-entity-heuristics.mjs +431 -0
- package/core-mapping-form.cjs +5 -0
- package/core-mapping-form.d.cts +2 -0
- package/core-mapping-form.d.mts +2 -0
- package/core-mapping-form.mjs +2 -0
- package/core-mapping-score.cjs +12 -0
- package/core-mapping-score.d.cts +2 -0
- package/core-mapping-score.d.mts +2 -0
- package/core-mapping-score.mjs +2 -0
- package/core-mappings-config.cjs +3 -0
- package/core-mappings-config.d.cts +2 -0
- package/core-mappings-config.d.mts +2 -0
- package/core-mappings-config.mjs +2 -0
- package/core-sync-engine.cjs +6 -0
- package/core-sync-engine.d.cts +2 -0
- package/core-sync-engine.d.mts +2 -0
- package/core-sync-engine.mjs +2 -0
- package/core-types.cjs +0 -0
- package/core-types.d.cts +2 -0
- package/core-types.d.mts +2 -0
- package/core-types.mjs +1 -0
- package/core-view-compiler.cjs +5 -0
- package/core-view-compiler.d.cts +2 -0
- package/core-view-compiler.d.mts +2 -0
- package/core-view-compiler.mjs +2 -0
- package/core.cjs +27 -0
- package/core.d.cts +9 -0
- package/core.d.mts +9 -0
- package/core.mjs +7 -0
- package/drizzle-meta-BGn0BqGb.cjs +9 -0
- package/drizzle-meta-CnC336L-.mjs +4 -0
- package/drizzle.cjs +107 -0
- package/drizzle.d.cts +28 -0
- package/drizzle.d.mts +28 -0
- package/drizzle.mjs +105 -0
- package/entity-config-Cvjo1cpv.cjs +4598 -0
- package/entity-config-D1DFyeUp.d.mts +2403 -0
- package/entity-config-DoR0khce.mjs +4533 -0
- package/entity-config-GczjD3y8.d.cts +2403 -0
- package/index.cjs +961 -0
- package/index.d.cts +57 -0
- package/index.d.mts +57 -0
- package/index.mjs +960 -0
- package/mapping-form-BHtPexzI.mjs +47 -0
- package/mapping-form-CUlFVfG8.d.cts +35 -0
- package/mapping-form-DdmDebC3.cjs +64 -0
- package/mapping-form-kjSiJaCX.d.mts +35 -0
- package/mapping-score-A2lRnlpk.d.mts +49 -0
- package/mapping-score-BJNe0lFn.mjs +87 -0
- package/mapping-score-BcjC0ZQs.d.cts +49 -0
- package/mapping-score-D9gfhtRu.cjs +146 -0
- package/mappings-config-CYPrzB3K.mjs +99 -0
- package/mappings-config-DTu_2cyx.cjs +104 -0
- package/mappings-config-DjRLCb2Q.d.cts +42 -0
- package/mappings-config-GxiYsSBQ.d.mts +42 -0
- package/namespace-probe-BtS0nXcr.d.cts +299 -0
- package/namespace-probe-CYMie-BI.d.mts +299 -0
- package/package.json +244 -21
- package/sdk-BZUn6wzs.mjs +764 -0
- package/sdk-CP_mYZa5.cjs +793 -0
- package/sdk.cjs +7 -0
- package/sdk.d.cts +33 -0
- package/sdk.d.mts +33 -0
- package/sdk.mjs +2 -0
- package/sync-engine-DUc0qWgo.cjs +230 -0
- package/sync-engine-DWnQPjV3.d.mts +183 -0
- package/sync-engine-DedXngop.mjs +207 -0
- package/sync-engine-uhfzKM-e.d.cts +183 -0
- package/types-BpsKVccL.d.cts +159 -0
- package/types-_qbJXMt_.d.mts +159 -0
- package/view-compiler-B4UYTvRM.d.cts +71 -0
- package/view-compiler-BHzbI9b7.cjs +202 -0
- package/view-compiler-CosFGar8.mjs +185 -0
- package/view-compiler-i_xFf-L0.d.mts +71 -0
- package/vite.cjs +38 -0
- package/vite.d.cts +23 -0
- package/vite.d.mts +23 -0
- package/vite.mjs +37 -0
- package/dist/index.mjs +0 -542
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { a as Scored } from "./mapping-score-BcjC0ZQs.cjs";
|
|
2
|
+
|
|
3
|
+
//#region ../core/src/entity-heuristics.d.ts
|
|
4
|
+
declare const TARGET_CONCEPTS: readonly ["contact", "company", "deal", "activity", "conversation", "note"];
|
|
5
|
+
type TargetConcept = (typeof TARGET_CONCEPTS)[number];
|
|
6
|
+
declare function suggestCursorField(columnKeys: string[]): string | null;
|
|
7
|
+
declare function matchesConcept(tableName: string, concept: TargetConcept): {
|
|
8
|
+
exact: boolean;
|
|
9
|
+
} | null;
|
|
10
|
+
interface DiscoveredColumnMeta {
|
|
11
|
+
isForeignKey?: boolean;
|
|
12
|
+
isPrimaryKey?: boolean;
|
|
13
|
+
name: string;
|
|
14
|
+
nullable?: boolean;
|
|
15
|
+
references?: {
|
|
16
|
+
table: string;
|
|
17
|
+
column: string;
|
|
18
|
+
};
|
|
19
|
+
type?: string;
|
|
20
|
+
}
|
|
21
|
+
interface ScoredTable {
|
|
22
|
+
columns: string[];
|
|
23
|
+
columnsMeta?: DiscoveredColumnMeta[];
|
|
24
|
+
name: string;
|
|
25
|
+
rowCount?: number;
|
|
26
|
+
}
|
|
27
|
+
declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
|
|
28
|
+
declare function topConcept(table: ScoredTable): {
|
|
29
|
+
best: Scored<TargetConcept>;
|
|
30
|
+
ambiguous: boolean;
|
|
31
|
+
} | null;
|
|
32
|
+
declare function requiredFieldsFor(concept: TargetConcept | "custom"): string[];
|
|
33
|
+
declare function validateMapping(requiredFields: string[], fieldMap: Record<string, string>): {
|
|
34
|
+
valid: boolean;
|
|
35
|
+
missing: string[];
|
|
36
|
+
};
|
|
37
|
+
declare function suggestDiscriminatorColumns(columns: string[]): string[];
|
|
38
|
+
type SuggestedVia = {
|
|
39
|
+
fkOn: "company" | "contact";
|
|
40
|
+
column: string;
|
|
41
|
+
} | {
|
|
42
|
+
through: string;
|
|
43
|
+
localKey: string;
|
|
44
|
+
foreignKey: string;
|
|
45
|
+
};
|
|
46
|
+
interface RelationshipSuggestion {
|
|
47
|
+
/** The related host table. */
|
|
48
|
+
entityTable: string;
|
|
49
|
+
/** Suggested relationship name (defaults to the related concept). */
|
|
50
|
+
name: string;
|
|
51
|
+
via: SuggestedVia;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Suggest contact→company relationships. When the source table carries FK
|
|
55
|
+
* metadata (`references`), the target table is a *fact*, not a name guess —
|
|
56
|
+
* that scores highest. Without metadata (v1 hosts) we fall back to the legacy
|
|
57
|
+
* FK-name hints at a lower tier.
|
|
58
|
+
*/
|
|
59
|
+
declare function scoreRelationships(source: ScoredTable, allTables: ScoredTable[]): Scored<RelationshipSuggestion>[];
|
|
60
|
+
interface FieldSuggestion {
|
|
61
|
+
column: string;
|
|
62
|
+
field: string;
|
|
63
|
+
required: boolean;
|
|
64
|
+
}
|
|
65
|
+
declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
|
|
66
|
+
declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
|
|
67
|
+
//#endregion
|
|
68
|
+
export { DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { a as Scored } from "./mapping-score-A2lRnlpk.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../core/src/entity-heuristics.d.ts
|
|
4
|
+
declare const TARGET_CONCEPTS: readonly ["contact", "company", "deal", "activity", "conversation", "note"];
|
|
5
|
+
type TargetConcept = (typeof TARGET_CONCEPTS)[number];
|
|
6
|
+
declare function suggestCursorField(columnKeys: string[]): string | null;
|
|
7
|
+
declare function matchesConcept(tableName: string, concept: TargetConcept): {
|
|
8
|
+
exact: boolean;
|
|
9
|
+
} | null;
|
|
10
|
+
interface DiscoveredColumnMeta {
|
|
11
|
+
isForeignKey?: boolean;
|
|
12
|
+
isPrimaryKey?: boolean;
|
|
13
|
+
name: string;
|
|
14
|
+
nullable?: boolean;
|
|
15
|
+
references?: {
|
|
16
|
+
table: string;
|
|
17
|
+
column: string;
|
|
18
|
+
};
|
|
19
|
+
type?: string;
|
|
20
|
+
}
|
|
21
|
+
interface ScoredTable {
|
|
22
|
+
columns: string[];
|
|
23
|
+
columnsMeta?: DiscoveredColumnMeta[];
|
|
24
|
+
name: string;
|
|
25
|
+
rowCount?: number;
|
|
26
|
+
}
|
|
27
|
+
declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
|
|
28
|
+
declare function topConcept(table: ScoredTable): {
|
|
29
|
+
best: Scored<TargetConcept>;
|
|
30
|
+
ambiguous: boolean;
|
|
31
|
+
} | null;
|
|
32
|
+
declare function requiredFieldsFor(concept: TargetConcept | "custom"): string[];
|
|
33
|
+
declare function validateMapping(requiredFields: string[], fieldMap: Record<string, string>): {
|
|
34
|
+
valid: boolean;
|
|
35
|
+
missing: string[];
|
|
36
|
+
};
|
|
37
|
+
declare function suggestDiscriminatorColumns(columns: string[]): string[];
|
|
38
|
+
type SuggestedVia = {
|
|
39
|
+
fkOn: "company" | "contact";
|
|
40
|
+
column: string;
|
|
41
|
+
} | {
|
|
42
|
+
through: string;
|
|
43
|
+
localKey: string;
|
|
44
|
+
foreignKey: string;
|
|
45
|
+
};
|
|
46
|
+
interface RelationshipSuggestion {
|
|
47
|
+
/** The related host table. */
|
|
48
|
+
entityTable: string;
|
|
49
|
+
/** Suggested relationship name (defaults to the related concept). */
|
|
50
|
+
name: string;
|
|
51
|
+
via: SuggestedVia;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Suggest contact→company relationships. When the source table carries FK
|
|
55
|
+
* metadata (`references`), the target table is a *fact*, not a name guess —
|
|
56
|
+
* that scores highest. Without metadata (v1 hosts) we fall back to the legacy
|
|
57
|
+
* FK-name hints at a lower tier.
|
|
58
|
+
*/
|
|
59
|
+
declare function scoreRelationships(source: ScoredTable, allTables: ScoredTable[]): Scored<RelationshipSuggestion>[];
|
|
60
|
+
interface FieldSuggestion {
|
|
61
|
+
column: string;
|
|
62
|
+
field: string;
|
|
63
|
+
required: boolean;
|
|
64
|
+
}
|
|
65
|
+
declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
|
|
66
|
+
declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
|
|
67
|
+
//#endregion
|
|
68
|
+
export { DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { a as MATERIALIZING_CONCEPTS } from "./entity-config-DoR0khce.mjs";
|
|
2
|
+
import { a as W, c as isTextLike, i as RELATIONSHIP_TIERS, l as isTimestampLike, n as CONCEPT_TIERS, o as isAmbiguous, r as FIELD_TIERS, s as isNumericLike, u as tierFor } from "./mapping-score-BJNe0lFn.mjs";
|
|
3
|
+
//#region ../core/src/entity-heuristics.ts
|
|
4
|
+
const TARGET_CONCEPTS = [
|
|
5
|
+
"contact",
|
|
6
|
+
"company",
|
|
7
|
+
"deal",
|
|
8
|
+
"activity",
|
|
9
|
+
"conversation",
|
|
10
|
+
"note"
|
|
11
|
+
];
|
|
12
|
+
const TABLE_PATTERNS = [
|
|
13
|
+
{
|
|
14
|
+
concept: "contact",
|
|
15
|
+
names: [
|
|
16
|
+
"users",
|
|
17
|
+
"customers",
|
|
18
|
+
"clients",
|
|
19
|
+
"accounts",
|
|
20
|
+
"participants",
|
|
21
|
+
"attendees",
|
|
22
|
+
"people",
|
|
23
|
+
"members",
|
|
24
|
+
"contacts"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
concept: "company",
|
|
29
|
+
names: [
|
|
30
|
+
"companies",
|
|
31
|
+
"organizations",
|
|
32
|
+
"organisations",
|
|
33
|
+
"orgs",
|
|
34
|
+
"teams",
|
|
35
|
+
"businesses",
|
|
36
|
+
"accounts"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
concept: "deal",
|
|
41
|
+
names: [
|
|
42
|
+
"deals",
|
|
43
|
+
"opportunities",
|
|
44
|
+
"subscriptions",
|
|
45
|
+
"orders",
|
|
46
|
+
"invoices",
|
|
47
|
+
"sales"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
concept: "conversation",
|
|
52
|
+
names: [
|
|
53
|
+
"conversations",
|
|
54
|
+
"messages",
|
|
55
|
+
"tickets",
|
|
56
|
+
"threads",
|
|
57
|
+
"chats",
|
|
58
|
+
"inbox"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
concept: "activity",
|
|
63
|
+
names: [
|
|
64
|
+
"events",
|
|
65
|
+
"activities",
|
|
66
|
+
"jobs",
|
|
67
|
+
"logs",
|
|
68
|
+
"audit",
|
|
69
|
+
"shifts",
|
|
70
|
+
"scans",
|
|
71
|
+
"sessions"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
concept: "note",
|
|
76
|
+
names: [
|
|
77
|
+
"notes",
|
|
78
|
+
"comments",
|
|
79
|
+
"annotations"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
];
|
|
83
|
+
const CONCEPT_FIELDS = {
|
|
84
|
+
contact: [{
|
|
85
|
+
field: "name",
|
|
86
|
+
candidates: [
|
|
87
|
+
"name",
|
|
88
|
+
"full_name",
|
|
89
|
+
"fullname",
|
|
90
|
+
"display_name"
|
|
91
|
+
],
|
|
92
|
+
required: false
|
|
93
|
+
}, {
|
|
94
|
+
field: "email",
|
|
95
|
+
candidates: ["email", "email_address"],
|
|
96
|
+
required: true
|
|
97
|
+
}],
|
|
98
|
+
company: [{
|
|
99
|
+
field: "name",
|
|
100
|
+
candidates: [
|
|
101
|
+
"name",
|
|
102
|
+
"company_name",
|
|
103
|
+
"legal_name",
|
|
104
|
+
"title"
|
|
105
|
+
],
|
|
106
|
+
required: true
|
|
107
|
+
}, {
|
|
108
|
+
field: "domain",
|
|
109
|
+
candidates: [
|
|
110
|
+
"domain",
|
|
111
|
+
"website",
|
|
112
|
+
"url"
|
|
113
|
+
],
|
|
114
|
+
required: false
|
|
115
|
+
}],
|
|
116
|
+
deal: [
|
|
117
|
+
{
|
|
118
|
+
field: "name",
|
|
119
|
+
candidates: ["name", "title"],
|
|
120
|
+
required: true
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
field: "value",
|
|
124
|
+
candidates: [
|
|
125
|
+
"value",
|
|
126
|
+
"amount",
|
|
127
|
+
"total",
|
|
128
|
+
"price"
|
|
129
|
+
],
|
|
130
|
+
required: false
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
field: "stage",
|
|
134
|
+
candidates: [
|
|
135
|
+
"stage",
|
|
136
|
+
"status",
|
|
137
|
+
"state"
|
|
138
|
+
],
|
|
139
|
+
required: false
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
activity: [
|
|
143
|
+
{
|
|
144
|
+
field: "type",
|
|
145
|
+
candidates: [
|
|
146
|
+
"type",
|
|
147
|
+
"kind",
|
|
148
|
+
"event_type"
|
|
149
|
+
],
|
|
150
|
+
required: false
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
field: "summary",
|
|
154
|
+
candidates: [
|
|
155
|
+
"summary",
|
|
156
|
+
"description",
|
|
157
|
+
"message",
|
|
158
|
+
"title"
|
|
159
|
+
],
|
|
160
|
+
required: false
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
field: "createdAt",
|
|
164
|
+
candidates: [
|
|
165
|
+
"created_at",
|
|
166
|
+
"createdat",
|
|
167
|
+
"timestamp"
|
|
168
|
+
],
|
|
169
|
+
required: false
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
conversation: [{
|
|
173
|
+
field: "status",
|
|
174
|
+
candidates: ["status", "state"],
|
|
175
|
+
required: false
|
|
176
|
+
}, {
|
|
177
|
+
field: "subject",
|
|
178
|
+
candidates: [
|
|
179
|
+
"subject",
|
|
180
|
+
"title",
|
|
181
|
+
"preview"
|
|
182
|
+
],
|
|
183
|
+
required: false
|
|
184
|
+
}],
|
|
185
|
+
note: [{
|
|
186
|
+
field: "body",
|
|
187
|
+
candidates: [
|
|
188
|
+
"body",
|
|
189
|
+
"content",
|
|
190
|
+
"text",
|
|
191
|
+
"note"
|
|
192
|
+
],
|
|
193
|
+
required: true
|
|
194
|
+
}]
|
|
195
|
+
};
|
|
196
|
+
const CURSOR_CANDIDATES = [
|
|
197
|
+
"updatedat",
|
|
198
|
+
"updated_at",
|
|
199
|
+
"modifiedat",
|
|
200
|
+
"modified_at",
|
|
201
|
+
"createdat",
|
|
202
|
+
"created_at"
|
|
203
|
+
];
|
|
204
|
+
function suggestCursorField(columnKeys) {
|
|
205
|
+
const lowerToActual = new Map(columnKeys.map((c) => [c.toLowerCase(), c]));
|
|
206
|
+
for (const candidate of CURSOR_CANDIDATES) {
|
|
207
|
+
const match = lowerToActual.get(candidate);
|
|
208
|
+
if (match) return match;
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
const MATERIALIZING = new Set(MATERIALIZING_CONCEPTS);
|
|
213
|
+
function matchesConcept(tableName, concept) {
|
|
214
|
+
const normalized = tableName.toLowerCase();
|
|
215
|
+
const entry = TABLE_PATTERNS.find((p) => p.concept === concept);
|
|
216
|
+
if (!entry) return null;
|
|
217
|
+
if (entry.names.includes(normalized)) return { exact: true };
|
|
218
|
+
if (entry.names.some((name) => normalized.includes(name))) return { exact: false };
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
function metaFor(table, column) {
|
|
222
|
+
return table.columnsMeta?.find((c) => c.name === column);
|
|
223
|
+
}
|
|
224
|
+
function hasDefiningColumn(concept, columns) {
|
|
225
|
+
const lower = new Set(columns.map((c) => c.toLowerCase()));
|
|
226
|
+
const required = CONCEPT_FIELDS[concept].filter((f) => f.required);
|
|
227
|
+
return required.length > 0 && required.every((f) => f.candidates.some((c) => lower.has(c)));
|
|
228
|
+
}
|
|
229
|
+
function scoreConcepts(table) {
|
|
230
|
+
const out = [];
|
|
231
|
+
for (const concept of TARGET_CONCEPTS) {
|
|
232
|
+
if (!MATERIALIZING.has(concept)) continue;
|
|
233
|
+
const nameMatch = matchesConcept(table.name, concept);
|
|
234
|
+
if (!nameMatch) continue;
|
|
235
|
+
let score = 0;
|
|
236
|
+
const reasons = [];
|
|
237
|
+
if (nameMatch.exact) {
|
|
238
|
+
score += W.nameExact;
|
|
239
|
+
reasons.push(`name matches "${table.name}"`);
|
|
240
|
+
} else {
|
|
241
|
+
score += W.nameSubstring;
|
|
242
|
+
reasons.push(`name looks like ${concept}`);
|
|
243
|
+
}
|
|
244
|
+
if (hasDefiningColumn(concept, table.columns)) {
|
|
245
|
+
score += W.definingColumn;
|
|
246
|
+
reasons.push(`has the columns a ${concept} needs`);
|
|
247
|
+
}
|
|
248
|
+
if (table.columnsMeta?.some((c) => c.isPrimaryKey)) {
|
|
249
|
+
score += W.hasPrimaryKey;
|
|
250
|
+
reasons.push("has primary key");
|
|
251
|
+
}
|
|
252
|
+
if (table.rowCount !== void 0) if (table.rowCount === 0) {
|
|
253
|
+
score += W.emptyTable;
|
|
254
|
+
reasons.push("table is empty");
|
|
255
|
+
} else {
|
|
256
|
+
score += W.hasRows;
|
|
257
|
+
reasons.push(`${table.rowCount.toLocaleString("en-US")} rows`);
|
|
258
|
+
}
|
|
259
|
+
out.push({
|
|
260
|
+
value: concept,
|
|
261
|
+
score,
|
|
262
|
+
tier: tierFor(score, CONCEPT_TIERS),
|
|
263
|
+
reasons
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return out.sort((a, b) => b.score - a.score);
|
|
267
|
+
}
|
|
268
|
+
function topConcept(table) {
|
|
269
|
+
const ranked = scoreConcepts(table);
|
|
270
|
+
const best = ranked[0];
|
|
271
|
+
if (!best) return null;
|
|
272
|
+
return {
|
|
273
|
+
best,
|
|
274
|
+
ambiguous: isAmbiguous(ranked)
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function requiredFieldsFor(concept) {
|
|
278
|
+
if (concept === "custom") return [];
|
|
279
|
+
return CONCEPT_FIELDS[concept].filter((f) => f.required).map((f) => f.field);
|
|
280
|
+
}
|
|
281
|
+
function validateMapping(requiredFields, fieldMap) {
|
|
282
|
+
const missing = requiredFields.filter((field) => !fieldMap[field]);
|
|
283
|
+
return {
|
|
284
|
+
valid: missing.length === 0,
|
|
285
|
+
missing
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
const DISCRIMINATOR_COLUMNS = [
|
|
289
|
+
"role",
|
|
290
|
+
"type",
|
|
291
|
+
"kind",
|
|
292
|
+
"status",
|
|
293
|
+
"state",
|
|
294
|
+
"category",
|
|
295
|
+
"tier"
|
|
296
|
+
];
|
|
297
|
+
function suggestDiscriminatorColumns(columns) {
|
|
298
|
+
const lowerToActual = new Map(columns.map((c) => [c.toLowerCase(), c]));
|
|
299
|
+
const out = [];
|
|
300
|
+
for (const name of DISCRIMINATOR_COLUMNS) {
|
|
301
|
+
const match = lowerToActual.get(name);
|
|
302
|
+
if (match) out.push(match);
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
const COMPANY_FK_HINTS = [
|
|
307
|
+
"organization_id",
|
|
308
|
+
"organisation_id",
|
|
309
|
+
"org_id",
|
|
310
|
+
"company_id",
|
|
311
|
+
"account_id",
|
|
312
|
+
"team_id"
|
|
313
|
+
];
|
|
314
|
+
function firstMatchingColumn(columns, hints) {
|
|
315
|
+
const lowerToActual = new Map(columns.map((c) => [c.toLowerCase(), c]));
|
|
316
|
+
for (const hint of hints) {
|
|
317
|
+
const match = lowerToActual.get(hint);
|
|
318
|
+
if (match) return match;
|
|
319
|
+
}
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Suggest contact→company relationships. When the source table carries FK
|
|
324
|
+
* metadata (`references`), the target table is a *fact*, not a name guess —
|
|
325
|
+
* that scores highest. Without metadata (v1 hosts) we fall back to the legacy
|
|
326
|
+
* FK-name hints at a lower tier.
|
|
327
|
+
*/
|
|
328
|
+
function scoreRelationships(source, allTables) {
|
|
329
|
+
const companyTables = allTables.filter((t) => t.name !== source.name && topConcept(t)?.best.value === "company");
|
|
330
|
+
if (companyTables.length === 0) return [];
|
|
331
|
+
const companyNames = new Set(companyTables.map((t) => t.name.toLowerCase()));
|
|
332
|
+
const out = [];
|
|
333
|
+
const seenTargets = /* @__PURE__ */ new Set();
|
|
334
|
+
for (const col of source.columnsMeta ?? []) {
|
|
335
|
+
const ref = col.references;
|
|
336
|
+
if (!(ref && companyNames.has(ref.table.toLowerCase()))) continue;
|
|
337
|
+
if (seenTargets.has(ref.table.toLowerCase())) continue;
|
|
338
|
+
seenTargets.add(ref.table.toLowerCase());
|
|
339
|
+
out.push({
|
|
340
|
+
value: {
|
|
341
|
+
name: "company",
|
|
342
|
+
entityTable: ref.table,
|
|
343
|
+
via: {
|
|
344
|
+
fkOn: "contact",
|
|
345
|
+
column: `${source.name}.${col.name}`
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
score: W.fkResolved,
|
|
349
|
+
tier: tierFor(W.fkResolved, RELATIONSHIP_TIERS),
|
|
350
|
+
reasons: [`foreign key → ${ref.table}.${ref.column}`]
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
if (source.columnsMeta?.length) return out.sort((a, b) => b.score - a.score);
|
|
354
|
+
const contactFk = firstMatchingColumn(source.columns, COMPANY_FK_HINTS);
|
|
355
|
+
if (contactFk) out.push({
|
|
356
|
+
value: {
|
|
357
|
+
name: "company",
|
|
358
|
+
entityTable: companyTables[0]?.name ?? "",
|
|
359
|
+
via: {
|
|
360
|
+
fkOn: "contact",
|
|
361
|
+
column: `${source.name}.${contactFk}`
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
score: W.fkNameHint,
|
|
365
|
+
tier: tierFor(W.fkNameHint, RELATIONSHIP_TIERS),
|
|
366
|
+
reasons: [`column "${contactFk}" looks like a company link`]
|
|
367
|
+
});
|
|
368
|
+
return out.sort((a, b) => b.score - a.score);
|
|
369
|
+
}
|
|
370
|
+
const FIELD_TYPE_EXPECTATION = {
|
|
371
|
+
name: "text",
|
|
372
|
+
email: "text",
|
|
373
|
+
domain: "text",
|
|
374
|
+
stage: "text",
|
|
375
|
+
status: "text",
|
|
376
|
+
subject: "text",
|
|
377
|
+
body: "text",
|
|
378
|
+
summary: "text",
|
|
379
|
+
type: "text",
|
|
380
|
+
value: "numeric",
|
|
381
|
+
createdAt: "timestamp"
|
|
382
|
+
};
|
|
383
|
+
function typeFits(field, type) {
|
|
384
|
+
const expectation = FIELD_TYPE_EXPECTATION[field];
|
|
385
|
+
if (!(expectation && type)) return null;
|
|
386
|
+
if (expectation === "text") return isTextLike(type);
|
|
387
|
+
if (expectation === "numeric") return isNumericLike(type);
|
|
388
|
+
return isTimestampLike(type);
|
|
389
|
+
}
|
|
390
|
+
function scoreFieldMap(concept, table) {
|
|
391
|
+
const lowerToActual = new Map(table.columns.map((c) => [c.toLowerCase(), c]));
|
|
392
|
+
const out = [];
|
|
393
|
+
for (const { field, candidates, required } of CONCEPT_FIELDS[concept]) for (const candidate of candidates) {
|
|
394
|
+
const column = lowerToActual.get(candidate);
|
|
395
|
+
if (!column) continue;
|
|
396
|
+
let score = W.fieldNameMatch;
|
|
397
|
+
const reasons = [`name matches "${column}"`];
|
|
398
|
+
const meta = metaFor(table, column);
|
|
399
|
+
const fits = typeFits(field, meta?.type);
|
|
400
|
+
if (fits === true) {
|
|
401
|
+
score += W.typeCompatible;
|
|
402
|
+
reasons.push(`type ${meta?.type}`);
|
|
403
|
+
} else if (fits === false) {
|
|
404
|
+
score += W.typeMismatch;
|
|
405
|
+
reasons.push(`type ${meta?.type} does not fit ${field}`);
|
|
406
|
+
}
|
|
407
|
+
if (required && meta?.nullable === false) {
|
|
408
|
+
score += W.requiredNotNull;
|
|
409
|
+
reasons.push("not null");
|
|
410
|
+
}
|
|
411
|
+
out.push({
|
|
412
|
+
value: {
|
|
413
|
+
field,
|
|
414
|
+
column,
|
|
415
|
+
required
|
|
416
|
+
},
|
|
417
|
+
score,
|
|
418
|
+
tier: tierFor(score, FIELD_TIERS),
|
|
419
|
+
reasons
|
|
420
|
+
});
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
return out;
|
|
424
|
+
}
|
|
425
|
+
function toFieldMap(scored) {
|
|
426
|
+
const map = {};
|
|
427
|
+
for (const { value } of scored) map[value.field] = value.column;
|
|
428
|
+
return map;
|
|
429
|
+
}
|
|
430
|
+
//#endregion
|
|
431
|
+
export { TARGET_CONCEPTS, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_mapping_form = require("./mapping-form-DdmDebC3.cjs");
|
|
3
|
+
exports.buildFilterFromDiscriminator = require_mapping_form.buildFilterFromDiscriminator;
|
|
4
|
+
exports.buildRelationships = require_mapping_form.buildRelationships;
|
|
5
|
+
exports.relationshipViaSignature = require_mapping_form.relationshipViaSignature;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_mapping_score = require("./mapping-score-D9gfhtRu.cjs");
|
|
3
|
+
exports.AMBIGUITY_MARGIN = require_mapping_score.AMBIGUITY_MARGIN;
|
|
4
|
+
exports.CONCEPT_TIERS = require_mapping_score.CONCEPT_TIERS;
|
|
5
|
+
exports.FIELD_TIERS = require_mapping_score.FIELD_TIERS;
|
|
6
|
+
exports.RELATIONSHIP_TIERS = require_mapping_score.RELATIONSHIP_TIERS;
|
|
7
|
+
exports.W = require_mapping_score.W;
|
|
8
|
+
exports.isAmbiguous = require_mapping_score.isAmbiguous;
|
|
9
|
+
exports.isNumericLike = require_mapping_score.isNumericLike;
|
|
10
|
+
exports.isTextLike = require_mapping_score.isTextLike;
|
|
11
|
+
exports.isTimestampLike = require_mapping_score.isTimestampLike;
|
|
12
|
+
exports.tierFor = require_mapping_score.tierFor;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as Scored, c as W, d as isTextLike, f as isTimestampLike, i as RELATIONSHIP_TIERS, l as isAmbiguous, n as CONCEPT_TIERS, o as Thresholds, p as tierFor, r as FIELD_TIERS, s as Tier, t as AMBIGUITY_MARGIN, u as isNumericLike } from "./mapping-score-BcjC0ZQs.cjs";
|
|
2
|
+
export { AMBIGUITY_MARGIN, CONCEPT_TIERS, FIELD_TIERS, RELATIONSHIP_TIERS, Scored, Thresholds, Tier, W, isAmbiguous, isNumericLike, isTextLike, isTimestampLike, tierFor };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as Scored, c as W, d as isTextLike, f as isTimestampLike, i as RELATIONSHIP_TIERS, l as isAmbiguous, n as CONCEPT_TIERS, o as Thresholds, p as tierFor, r as FIELD_TIERS, s as Tier, t as AMBIGUITY_MARGIN, u as isNumericLike } from "./mapping-score-A2lRnlpk.mjs";
|
|
2
|
+
export { AMBIGUITY_MARGIN, CONCEPT_TIERS, FIELD_TIERS, RELATIONSHIP_TIERS, Scored, Thresholds, Tier, W, isAmbiguous, isNumericLike, isTextLike, isTimestampLike, tierFor };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as W, c as isTextLike, i as RELATIONSHIP_TIERS, l as isTimestampLike, n as CONCEPT_TIERS, o as isAmbiguous, r as FIELD_TIERS, s as isNumericLike, t as AMBIGUITY_MARGIN, u as tierFor } from "./mapping-score-BJNe0lFn.mjs";
|
|
2
|
+
export { AMBIGUITY_MARGIN, CONCEPT_TIERS, FIELD_TIERS, RELATIONSHIP_TIERS, W, isAmbiguous, isNumericLike, isTextLike, isTimestampLike, tierFor };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_sync_engine = require("./sync-engine-DUc0qWgo.cjs");
|
|
3
|
+
exports.computeSampleWarnings = require_sync_engine.computeSampleWarnings;
|
|
4
|
+
exports.previewSync = require_sync_engine.previewSync;
|
|
5
|
+
exports.reconcile = require_sync_engine.reconcile;
|
|
6
|
+
exports.runSync = require_sync_engine.runSync;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as PreviewWarning, c as SyncResult, d as previewSync, f as reconcile, i as PreviewResult, l as SyncStore, n as MirrorRecord, o as SourceRow, p as runSync, r as PersistAction, s as SyncAction, t as EntitySyncResult, u as computeSampleWarnings } from "./sync-engine-uhfzKM-e.cjs";
|
|
2
|
+
export { EntitySyncResult, MirrorRecord, PersistAction, PreviewResult, PreviewWarning, SourceRow, SyncAction, SyncResult, SyncStore, computeSampleWarnings, previewSync, reconcile, runSync };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as PreviewWarning, c as SyncResult, d as previewSync, f as reconcile, i as PreviewResult, l as SyncStore, n as MirrorRecord, o as SourceRow, p as runSync, r as PersistAction, s as SyncAction, t as EntitySyncResult, u as computeSampleWarnings } from "./sync-engine-DWnQPjV3.mjs";
|
|
2
|
+
export { EntitySyncResult, MirrorRecord, PersistAction, PreviewResult, PreviewWarning, SourceRow, SyncAction, SyncResult, SyncStore, computeSampleWarnings, previewSync, reconcile, runSync };
|
package/core-types.cjs
ADDED
|
File without changes
|
package/core-types.d.cts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { C as UpdateDealInput, S as UpdateContactInput, _ as Task, a as ContactFilters, b as TaskPriority, c as CreateCompanyInput, d as CreateTaskInput, f as CrmRole, g as RecordSource, h as Note, i as Contact, l as CreateContactInput, m as DealStage, n as ActivityType, o as ContactStatus, p as Deal, r as Company, s as CreateActivityInput, t as Activity, u as CreateDealInput, v as TaskEntityType, w as UpdateTaskInput, x as TaskStatus, y as TaskFilters } from "./types-BpsKVccL.cjs";
|
|
2
|
+
export { Activity, ActivityType, Company, Contact, ContactFilters, ContactStatus, CreateActivityInput, CreateCompanyInput, CreateContactInput, CreateDealInput, CreateTaskInput, CrmRole, Deal, DealStage, Note, RecordSource, Task, TaskEntityType, TaskFilters, TaskPriority, TaskStatus, UpdateContactInput, UpdateDealInput, UpdateTaskInput };
|
package/core-types.d.mts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { C as UpdateDealInput, S as UpdateContactInput, _ as Task, a as ContactFilters, b as TaskPriority, c as CreateCompanyInput, d as CreateTaskInput, f as CrmRole, g as RecordSource, h as Note, i as Contact, l as CreateContactInput, m as DealStage, n as ActivityType, o as ContactStatus, p as Deal, r as Company, s as CreateActivityInput, t as Activity, u as CreateDealInput, v as TaskEntityType, w as UpdateTaskInput, x as TaskStatus, y as TaskFilters } from "./types-_qbJXMt_.mjs";
|
|
2
|
+
export { Activity, ActivityType, Company, Contact, ContactFilters, ContactStatus, CreateActivityInput, CreateCompanyInput, CreateContactInput, CreateDealInput, CreateTaskInput, CrmRole, Deal, DealStage, Note, RecordSource, Task, TaskEntityType, TaskFilters, TaskPriority, TaskStatus, UpdateContactInput, UpdateDealInput, UpdateTaskInput };
|
package/core-types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_view_compiler = require("./view-compiler-BHzbI9b7.cjs");
|
|
3
|
+
exports.compileEntityView = require_view_compiler.compileEntityView;
|
|
4
|
+
exports.compileEntityViews = require_view_compiler.compileEntityViews;
|
|
5
|
+
exports.explainEntitiesConfig = require_view_compiler.explainEntitiesConfig;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as compileEntityViews, i as compileEntityView, n as CompiledView, o as explainEntitiesConfig, r as ExplainResult, t as CompileOptions } from "./view-compiler-B4UYTvRM.cjs";
|
|
2
|
+
export { CompileOptions, CompiledView, ExplainResult, compileEntityView, compileEntityViews, explainEntitiesConfig };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as compileEntityViews, i as compileEntityView, n as CompiledView, o as explainEntitiesConfig, r as ExplainResult, t as CompileOptions } from "./view-compiler-i_xFf-L0.mjs";
|
|
2
|
+
export { CompileOptions, CompiledView, ExplainResult, compileEntityView, compileEntityViews, explainEntitiesConfig };
|