@clivly/core 0.10.9 → 0.11.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.
- package/dist/adapter.d.cts +44 -7
- package/dist/adapter.d.mts +44 -7
- package/dist/auth-adapter.d.cts +6 -7
- package/dist/auth-adapter.d.mts +6 -7
- package/dist/builder.d.cts +12 -12
- package/dist/builder.d.mts +12 -12
- package/dist/drizzle.d.cts +5 -6
- package/dist/drizzle.d.mts +5 -6
- package/dist/{entity-config-C_NDVfrL.mjs → entity-config-C0rtu-K_.mjs} +20 -2
- package/dist/{entity-config-J5KYJVTO.cjs → entity-config-C2sKAti2.cjs} +20 -2
- package/dist/{entity-config-ChHLozko.d.cts → entity-config-OhC4Otkz.d.cts} +4 -2
- package/dist/{entity-config-ChHLozko.d.mts → entity-config-OhC4Otkz.d.mts} +4 -2
- package/dist/entity-config.cjs +1 -1
- package/dist/entity-config.d.cts +1 -1
- package/dist/entity-config.d.mts +1 -1
- package/dist/entity-config.mjs +1 -1
- package/dist/entity-heuristics.cjs +43 -24
- package/dist/entity-heuristics.d.cts +21 -21
- package/dist/entity-heuristics.d.mts +21 -21
- package/dist/entity-heuristics.mjs +43 -24
- package/dist/env-file.d.cts +6 -7
- package/dist/env-file.d.mts +6 -7
- package/dist/index.cjs +83 -1
- package/dist/index.d.cts +89 -22
- package/dist/index.d.mts +89 -22
- package/dist/index.mjs +80 -2
- package/dist/integration-state.d.cts +30 -31
- package/dist/integration-state.d.mts +30 -31
- package/dist/mapping-form.d.cts +6 -7
- package/dist/mapping-form.d.mts +6 -7
- package/dist/mapping-score.d.cts +14 -15
- package/dist/mapping-score.d.mts +14 -15
- package/dist/mappings-config.cjs +2 -1
- package/dist/mappings-config.d.cts +8 -7
- package/dist/mappings-config.d.mts +8 -7
- package/dist/mappings-config.mjs +2 -1
- package/dist/sync-engine.d.cts +15 -16
- package/dist/sync-engine.d.mts +15 -16
- package/dist/types.d.cts +99 -33
- package/dist/types.d.mts +99 -33
- package/dist/view-compiler.d.cts +10 -11
- package/dist/view-compiler.d.mts +10 -11
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_entity_config = require("./entity-config-
|
|
2
|
+
const require_entity_config = require("./entity-config-C2sKAti2.cjs");
|
|
3
3
|
const require_mapping_score = require("./mapping-score.cjs");
|
|
4
4
|
//#region src/entity-heuristics.ts
|
|
5
5
|
const TARGET_CONCEPTS = [
|
|
@@ -95,23 +95,39 @@ const TABLE_PATTERNS = [
|
|
|
95
95
|
}
|
|
96
96
|
];
|
|
97
97
|
const CONCEPT_FIELDS = {
|
|
98
|
-
contact: [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
98
|
+
contact: [
|
|
99
|
+
{
|
|
100
|
+
field: "name",
|
|
101
|
+
candidates: [
|
|
102
|
+
"name",
|
|
103
|
+
"full_name",
|
|
104
|
+
"fullname",
|
|
105
|
+
"display_name",
|
|
106
|
+
"first_name",
|
|
107
|
+
"firstname",
|
|
108
|
+
"given_name"
|
|
109
|
+
],
|
|
110
|
+
required: false
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
field: "email",
|
|
114
|
+
candidates: ["email", "email_address"],
|
|
115
|
+
required: true
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
field: "phone",
|
|
119
|
+
candidates: [
|
|
120
|
+
"phone",
|
|
121
|
+
"phone_number",
|
|
122
|
+
"phonenumber",
|
|
123
|
+
"mobile",
|
|
124
|
+
"mobile_number",
|
|
125
|
+
"mobilenumber",
|
|
126
|
+
"telephone"
|
|
127
|
+
],
|
|
128
|
+
required: false
|
|
129
|
+
}
|
|
130
|
+
],
|
|
115
131
|
company: [{
|
|
116
132
|
field: "name",
|
|
117
133
|
candidates: [
|
|
@@ -363,12 +379,14 @@ function scoreConcepts(table) {
|
|
|
363
379
|
score += require_mapping_score.W.hasPrimaryKey;
|
|
364
380
|
reasons.push("has primary key");
|
|
365
381
|
}
|
|
366
|
-
if (table.rowCount !== void 0)
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
382
|
+
if (table.rowCount !== void 0) {
|
|
383
|
+
if (table.rowCount === 0) {
|
|
384
|
+
score += require_mapping_score.W.emptyTable;
|
|
385
|
+
reasons.push("table is empty");
|
|
386
|
+
} else {
|
|
387
|
+
score += require_mapping_score.W.hasRows;
|
|
388
|
+
reasons.push(`${table.rowCount.toLocaleString("en-US")} rows`);
|
|
389
|
+
}
|
|
372
390
|
}
|
|
373
391
|
out.push({
|
|
374
392
|
value: concept,
|
|
@@ -484,6 +502,7 @@ function scoreRelationships(source, allTables) {
|
|
|
484
502
|
const FIELD_TYPE_EXPECTATION = {
|
|
485
503
|
name: "text",
|
|
486
504
|
email: "text",
|
|
505
|
+
phone: "text",
|
|
487
506
|
domain: "text",
|
|
488
507
|
stage: "text",
|
|
489
508
|
status: "text",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { p as DiscoveredColumnMeta } from "./entity-config-
|
|
1
|
+
import { p as DiscoveredColumnMeta } from "./entity-config-OhC4Otkz.cjs";
|
|
2
2
|
import { Scored } from "./mapping-score.cjs";
|
|
3
3
|
//#region 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): {
|
|
4
|
+
export declare const TARGET_CONCEPTS: readonly ["contact", "company", "deal", "activity", "conversation", "note"];
|
|
5
|
+
export type TargetConcept = (typeof TARGET_CONCEPTS)[number];
|
|
6
|
+
export declare function suggestCursorField(columnKeys: string[]): string | null;
|
|
7
|
+
export declare function matchesConcept(tableName: string, concept: TargetConcept): {
|
|
8
8
|
exact: boolean;
|
|
9
9
|
} | null;
|
|
10
|
-
interface ScoredTable {
|
|
10
|
+
export interface ScoredTable {
|
|
11
11
|
columns: string[];
|
|
12
12
|
columnsMeta?: DiscoveredColumnMeta[];
|
|
13
13
|
name: string;
|
|
@@ -18,7 +18,7 @@ interface ScoredTable {
|
|
|
18
18
|
* and from bulk apply, so one click can never map an auth table into the CRM.
|
|
19
19
|
* They stay manually selectable — an explicit, informed choice is legitimate.
|
|
20
20
|
*/
|
|
21
|
-
declare function hasSensitiveColumns(columns: string[]): boolean;
|
|
21
|
+
export declare function hasSensitiveColumns(columns: string[]): boolean;
|
|
22
22
|
/**
|
|
23
23
|
* Is this table one your auth library created, rather than one you wrote?
|
|
24
24
|
*
|
|
@@ -26,20 +26,20 @@ declare function hasSensitiveColumns(columns: string[]): boolean;
|
|
|
26
26
|
* concept. Never to exclude them: mapping `user` as the contact entity is
|
|
27
27
|
* legitimate for plenty of apps, and it stays selectable.
|
|
28
28
|
*/
|
|
29
|
-
declare function isFrameworkTable(name: string): boolean;
|
|
30
|
-
declare function hasDefiningColumn(concept: TargetConcept, columns: string[]): boolean;
|
|
31
|
-
declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
|
|
32
|
-
declare function topConcept(table: ScoredTable): {
|
|
29
|
+
export declare function isFrameworkTable(name: string): boolean;
|
|
30
|
+
export declare function hasDefiningColumn(concept: TargetConcept, columns: string[]): boolean;
|
|
31
|
+
export declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
|
|
32
|
+
export declare function topConcept(table: ScoredTable): {
|
|
33
33
|
best: Scored<TargetConcept>;
|
|
34
34
|
ambiguous: boolean;
|
|
35
35
|
} | null;
|
|
36
|
-
declare function requiredFieldsFor(concept: TargetConcept | "custom"): string[];
|
|
37
|
-
declare function validateMapping(requiredFields: string[], fieldMap: Record<string, string>): {
|
|
36
|
+
export declare function requiredFieldsFor(concept: TargetConcept | "custom"): string[];
|
|
37
|
+
export declare function validateMapping(requiredFields: string[], fieldMap: Record<string, string>): {
|
|
38
38
|
valid: boolean;
|
|
39
39
|
missing: string[];
|
|
40
40
|
};
|
|
41
|
-
declare function suggestDiscriminatorColumns(columns: string[]): string[];
|
|
42
|
-
type SuggestedVia = {
|
|
41
|
+
export declare function suggestDiscriminatorColumns(columns: string[]): string[];
|
|
42
|
+
export type SuggestedVia = {
|
|
43
43
|
fkOn: "company" | "contact";
|
|
44
44
|
column: string;
|
|
45
45
|
} | {
|
|
@@ -47,7 +47,7 @@ type SuggestedVia = {
|
|
|
47
47
|
localKey: string;
|
|
48
48
|
foreignKey: string;
|
|
49
49
|
};
|
|
50
|
-
interface RelationshipSuggestion {
|
|
50
|
+
export interface RelationshipSuggestion {
|
|
51
51
|
/** The related host table. */
|
|
52
52
|
entityTable: string;
|
|
53
53
|
/** Suggested relationship name (defaults to the related concept). */
|
|
@@ -60,13 +60,13 @@ interface RelationshipSuggestion {
|
|
|
60
60
|
* that scores highest. Without metadata (v1 hosts) we fall back to the legacy
|
|
61
61
|
* FK-name hints at a lower tier.
|
|
62
62
|
*/
|
|
63
|
-
declare function scoreRelationships(source: ScoredTable, allTables: ScoredTable[]): Scored<RelationshipSuggestion>[];
|
|
64
|
-
interface FieldSuggestion {
|
|
63
|
+
export declare function scoreRelationships(source: ScoredTable, allTables: ScoredTable[]): Scored<RelationshipSuggestion>[];
|
|
64
|
+
export interface FieldSuggestion {
|
|
65
65
|
column: string;
|
|
66
66
|
field: string;
|
|
67
67
|
required: boolean;
|
|
68
68
|
}
|
|
69
|
-
declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
|
|
70
|
-
declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
|
|
69
|
+
export declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
|
|
70
|
+
export declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
|
|
71
71
|
//#endregion
|
|
72
|
-
export {
|
|
72
|
+
export type { DiscoveredColumnMeta };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { p as DiscoveredColumnMeta } from "./entity-config-
|
|
1
|
+
import { p as DiscoveredColumnMeta } from "./entity-config-OhC4Otkz.mjs";
|
|
2
2
|
import { Scored } from "./mapping-score.mjs";
|
|
3
3
|
//#region 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): {
|
|
4
|
+
export declare const TARGET_CONCEPTS: readonly ["contact", "company", "deal", "activity", "conversation", "note"];
|
|
5
|
+
export type TargetConcept = (typeof TARGET_CONCEPTS)[number];
|
|
6
|
+
export declare function suggestCursorField(columnKeys: string[]): string | null;
|
|
7
|
+
export declare function matchesConcept(tableName: string, concept: TargetConcept): {
|
|
8
8
|
exact: boolean;
|
|
9
9
|
} | null;
|
|
10
|
-
interface ScoredTable {
|
|
10
|
+
export interface ScoredTable {
|
|
11
11
|
columns: string[];
|
|
12
12
|
columnsMeta?: DiscoveredColumnMeta[];
|
|
13
13
|
name: string;
|
|
@@ -18,7 +18,7 @@ interface ScoredTable {
|
|
|
18
18
|
* and from bulk apply, so one click can never map an auth table into the CRM.
|
|
19
19
|
* They stay manually selectable — an explicit, informed choice is legitimate.
|
|
20
20
|
*/
|
|
21
|
-
declare function hasSensitiveColumns(columns: string[]): boolean;
|
|
21
|
+
export declare function hasSensitiveColumns(columns: string[]): boolean;
|
|
22
22
|
/**
|
|
23
23
|
* Is this table one your auth library created, rather than one you wrote?
|
|
24
24
|
*
|
|
@@ -26,20 +26,20 @@ declare function hasSensitiveColumns(columns: string[]): boolean;
|
|
|
26
26
|
* concept. Never to exclude them: mapping `user` as the contact entity is
|
|
27
27
|
* legitimate for plenty of apps, and it stays selectable.
|
|
28
28
|
*/
|
|
29
|
-
declare function isFrameworkTable(name: string): boolean;
|
|
30
|
-
declare function hasDefiningColumn(concept: TargetConcept, columns: string[]): boolean;
|
|
31
|
-
declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
|
|
32
|
-
declare function topConcept(table: ScoredTable): {
|
|
29
|
+
export declare function isFrameworkTable(name: string): boolean;
|
|
30
|
+
export declare function hasDefiningColumn(concept: TargetConcept, columns: string[]): boolean;
|
|
31
|
+
export declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
|
|
32
|
+
export declare function topConcept(table: ScoredTable): {
|
|
33
33
|
best: Scored<TargetConcept>;
|
|
34
34
|
ambiguous: boolean;
|
|
35
35
|
} | null;
|
|
36
|
-
declare function requiredFieldsFor(concept: TargetConcept | "custom"): string[];
|
|
37
|
-
declare function validateMapping(requiredFields: string[], fieldMap: Record<string, string>): {
|
|
36
|
+
export declare function requiredFieldsFor(concept: TargetConcept | "custom"): string[];
|
|
37
|
+
export declare function validateMapping(requiredFields: string[], fieldMap: Record<string, string>): {
|
|
38
38
|
valid: boolean;
|
|
39
39
|
missing: string[];
|
|
40
40
|
};
|
|
41
|
-
declare function suggestDiscriminatorColumns(columns: string[]): string[];
|
|
42
|
-
type SuggestedVia = {
|
|
41
|
+
export declare function suggestDiscriminatorColumns(columns: string[]): string[];
|
|
42
|
+
export type SuggestedVia = {
|
|
43
43
|
fkOn: "company" | "contact";
|
|
44
44
|
column: string;
|
|
45
45
|
} | {
|
|
@@ -47,7 +47,7 @@ type SuggestedVia = {
|
|
|
47
47
|
localKey: string;
|
|
48
48
|
foreignKey: string;
|
|
49
49
|
};
|
|
50
|
-
interface RelationshipSuggestion {
|
|
50
|
+
export interface RelationshipSuggestion {
|
|
51
51
|
/** The related host table. */
|
|
52
52
|
entityTable: string;
|
|
53
53
|
/** Suggested relationship name (defaults to the related concept). */
|
|
@@ -60,13 +60,13 @@ interface RelationshipSuggestion {
|
|
|
60
60
|
* that scores highest. Without metadata (v1 hosts) we fall back to the legacy
|
|
61
61
|
* FK-name hints at a lower tier.
|
|
62
62
|
*/
|
|
63
|
-
declare function scoreRelationships(source: ScoredTable, allTables: ScoredTable[]): Scored<RelationshipSuggestion>[];
|
|
64
|
-
interface FieldSuggestion {
|
|
63
|
+
export declare function scoreRelationships(source: ScoredTable, allTables: ScoredTable[]): Scored<RelationshipSuggestion>[];
|
|
64
|
+
export interface FieldSuggestion {
|
|
65
65
|
column: string;
|
|
66
66
|
field: string;
|
|
67
67
|
required: boolean;
|
|
68
68
|
}
|
|
69
|
-
declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
|
|
70
|
-
declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
|
|
69
|
+
export declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
|
|
70
|
+
export declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
|
|
71
71
|
//#endregion
|
|
72
|
-
export {
|
|
72
|
+
export type { DiscoveredColumnMeta };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as MATERIALIZING_CONCEPTS } from "./entity-config-
|
|
1
|
+
import { a as MATERIALIZING_CONCEPTS } from "./entity-config-C0rtu-K_.mjs";
|
|
2
2
|
import { CONCEPT_TIERS, FIELD_TIERS, RELATIONSHIP_TIERS, W, isAmbiguous, isNumericLike, isTextLike, isTimestampLike, tierFor } from "./mapping-score.mjs";
|
|
3
3
|
//#region src/entity-heuristics.ts
|
|
4
4
|
const TARGET_CONCEPTS = [
|
|
@@ -94,23 +94,39 @@ const TABLE_PATTERNS = [
|
|
|
94
94
|
}
|
|
95
95
|
];
|
|
96
96
|
const CONCEPT_FIELDS = {
|
|
97
|
-
contact: [
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
97
|
+
contact: [
|
|
98
|
+
{
|
|
99
|
+
field: "name",
|
|
100
|
+
candidates: [
|
|
101
|
+
"name",
|
|
102
|
+
"full_name",
|
|
103
|
+
"fullname",
|
|
104
|
+
"display_name",
|
|
105
|
+
"first_name",
|
|
106
|
+
"firstname",
|
|
107
|
+
"given_name"
|
|
108
|
+
],
|
|
109
|
+
required: false
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
field: "email",
|
|
113
|
+
candidates: ["email", "email_address"],
|
|
114
|
+
required: true
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
field: "phone",
|
|
118
|
+
candidates: [
|
|
119
|
+
"phone",
|
|
120
|
+
"phone_number",
|
|
121
|
+
"phonenumber",
|
|
122
|
+
"mobile",
|
|
123
|
+
"mobile_number",
|
|
124
|
+
"mobilenumber",
|
|
125
|
+
"telephone"
|
|
126
|
+
],
|
|
127
|
+
required: false
|
|
128
|
+
}
|
|
129
|
+
],
|
|
114
130
|
company: [{
|
|
115
131
|
field: "name",
|
|
116
132
|
candidates: [
|
|
@@ -362,12 +378,14 @@ function scoreConcepts(table) {
|
|
|
362
378
|
score += W.hasPrimaryKey;
|
|
363
379
|
reasons.push("has primary key");
|
|
364
380
|
}
|
|
365
|
-
if (table.rowCount !== void 0)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
381
|
+
if (table.rowCount !== void 0) {
|
|
382
|
+
if (table.rowCount === 0) {
|
|
383
|
+
score += W.emptyTable;
|
|
384
|
+
reasons.push("table is empty");
|
|
385
|
+
} else {
|
|
386
|
+
score += W.hasRows;
|
|
387
|
+
reasons.push(`${table.rowCount.toLocaleString("en-US")} rows`);
|
|
388
|
+
}
|
|
371
389
|
}
|
|
372
390
|
out.push({
|
|
373
391
|
value: concept,
|
|
@@ -483,6 +501,7 @@ function scoreRelationships(source, allTables) {
|
|
|
483
501
|
const FIELD_TYPE_EXPECTATION = {
|
|
484
502
|
name: "text",
|
|
485
503
|
email: "text",
|
|
504
|
+
phone: "text",
|
|
486
505
|
domain: "text",
|
|
487
506
|
stage: "text",
|
|
488
507
|
status: "text",
|
package/dist/env-file.d.cts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
//#region src/env-file.d.ts
|
|
2
|
-
declare const ENV_FRAMEWORKS: readonly ["next", "tanstack-start", "sveltekit", "remix", "nuxt", "hono-workers"];
|
|
3
|
-
type EnvFramework = (typeof ENV_FRAMEWORKS)[number];
|
|
2
|
+
export declare const ENV_FRAMEWORKS: readonly ["next", "tanstack-start", "sveltekit", "remix", "nuxt", "hono-workers"];
|
|
3
|
+
export type EnvFramework = (typeof ENV_FRAMEWORKS)[number];
|
|
4
4
|
/** The conventional env file for a framework. `.env` when we do not know. */
|
|
5
|
-
declare function envFileFor(framework: string | null | undefined): string;
|
|
5
|
+
export declare function envFileFor(framework: string | null | undefined): string;
|
|
6
6
|
/** The canonical id for a framework name, or null when unrecognised. */
|
|
7
|
-
declare function normalizeFramework(framework: string | null | undefined): EnvFramework | null;
|
|
7
|
+
export declare function normalizeFramework(framework: string | null | undefined): EnvFramework | null;
|
|
8
8
|
/**
|
|
9
9
|
* Which env file to actually write to.
|
|
10
10
|
*
|
|
@@ -14,10 +14,9 @@ declare function normalizeFramework(framework: string | null | undefined): EnvFr
|
|
|
14
14
|
* stale one still loading. Convention applies to new setups, not to a working
|
|
15
15
|
* one someone already has.
|
|
16
16
|
*/
|
|
17
|
-
declare function resolveEnvFile(input: {
|
|
17
|
+
export declare function resolveEnvFile(input: {
|
|
18
18
|
/** Candidate filenames that already contain the credential, if any. */
|
|
19
19
|
existing: string[];
|
|
20
20
|
framework: string | null | undefined;
|
|
21
21
|
}): string;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { ENV_FRAMEWORKS, EnvFramework, envFileFor, normalizeFramework, resolveEnvFile };
|
|
22
|
+
//#endregion
|
package/dist/env-file.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
//#region src/env-file.d.ts
|
|
2
|
-
declare const ENV_FRAMEWORKS: readonly ["next", "tanstack-start", "sveltekit", "remix", "nuxt", "hono-workers"];
|
|
3
|
-
type EnvFramework = (typeof ENV_FRAMEWORKS)[number];
|
|
2
|
+
export declare const ENV_FRAMEWORKS: readonly ["next", "tanstack-start", "sveltekit", "remix", "nuxt", "hono-workers"];
|
|
3
|
+
export type EnvFramework = (typeof ENV_FRAMEWORKS)[number];
|
|
4
4
|
/** The conventional env file for a framework. `.env` when we do not know. */
|
|
5
|
-
declare function envFileFor(framework: string | null | undefined): string;
|
|
5
|
+
export declare function envFileFor(framework: string | null | undefined): string;
|
|
6
6
|
/** The canonical id for a framework name, or null when unrecognised. */
|
|
7
|
-
declare function normalizeFramework(framework: string | null | undefined): EnvFramework | null;
|
|
7
|
+
export declare function normalizeFramework(framework: string | null | undefined): EnvFramework | null;
|
|
8
8
|
/**
|
|
9
9
|
* Which env file to actually write to.
|
|
10
10
|
*
|
|
@@ -14,10 +14,9 @@ declare function normalizeFramework(framework: string | null | undefined): EnvFr
|
|
|
14
14
|
* stale one still loading. Convention applies to new setups, not to a working
|
|
15
15
|
* one someone already has.
|
|
16
16
|
*/
|
|
17
|
-
declare function resolveEnvFile(input: {
|
|
17
|
+
export declare function resolveEnvFile(input: {
|
|
18
18
|
/** Candidate filenames that already contain the credential, if any. */
|
|
19
19
|
existing: string[];
|
|
20
20
|
framework: string | null | undefined;
|
|
21
21
|
}): string;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { ENV_FRAMEWORKS, EnvFramework, envFileFor, normalizeFramework, resolveEnvFile };
|
|
22
|
+
//#endregion
|
package/dist/index.cjs
CHANGED
|
@@ -2,12 +2,90 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_auth_adapter = require("./auth-adapter.cjs");
|
|
3
3
|
const require_projection = require("./projection-DFgCoyZl.cjs");
|
|
4
4
|
const require_schema_meta = require("./schema-meta-Cgi0MnHh.cjs");
|
|
5
|
-
const require_entity_config = require("./entity-config-
|
|
5
|
+
const require_entity_config = require("./entity-config-C2sKAti2.cjs");
|
|
6
6
|
const require_mapping_form = require("./mapping-form.cjs");
|
|
7
7
|
const require_mappings_config = require("./mappings-config.cjs");
|
|
8
8
|
const require_view_compiler = require("./view-compiler-DP4Fbj7-.cjs");
|
|
9
9
|
const require_sync_engine = require("./sync-engine.cjs");
|
|
10
10
|
const require_types = require("./types.cjs");
|
|
11
|
+
//#region src/host-owned-fields.ts
|
|
12
|
+
/**
|
|
13
|
+
* Which fields a CRM record lets a user edit.
|
|
14
|
+
*
|
|
15
|
+
* A record synced from the host app carries a `sourceRef`. Its identity fields
|
|
16
|
+
* are rewritten from the host view on every sync run, so an edit to one would
|
|
17
|
+
* be silently reverted minutes later — the user sees their change accepted,
|
|
18
|
+
* then gone, with nothing explaining why. That is worse than refusing it.
|
|
19
|
+
*
|
|
20
|
+
* So host-owned fields are rejected at the API, not merely disabled in the UI:
|
|
21
|
+
* the UI is not the security boundary, and the SDK and any future public API
|
|
22
|
+
* reach the same routers.
|
|
23
|
+
*
|
|
24
|
+
* Records created inside the CRM have no `sourceRef` and are fully editable —
|
|
25
|
+
* nothing else owns them.
|
|
26
|
+
*
|
|
27
|
+
* This is the cheap half of a capability matrix. It answers "may a user write
|
|
28
|
+
* this?" but not "may the sync engine write this?", which stays implicit
|
|
29
|
+
* because sync bypasses these routers entirely. An override model (the
|
|
30
|
+
* `stageOverrideAt` pattern on `crm_deals`) can replace this later without
|
|
31
|
+
* changing callers.
|
|
32
|
+
*/
|
|
33
|
+
/** Contact fields the host view owns when the row is synced. */
|
|
34
|
+
const HOST_OWNED_CONTACT_FIELDS = ["email", "name"];
|
|
35
|
+
/**
|
|
36
|
+
* Company fields the host view owns when the row is synced.
|
|
37
|
+
*
|
|
38
|
+
* `email` and `phone` joined this list in the same change that made them
|
|
39
|
+
* mappable (migration 0048). They are not identity fields, but ownership here
|
|
40
|
+
* follows what sync rewrites, not what feels identity-like: both flow from the
|
|
41
|
+
* host view on every run, exactly as `email` does for contacts above. Widening
|
|
42
|
+
* `CANONICAL_FIELDS.company` without widening this list is the specific bug
|
|
43
|
+
* this module's doc comment calls worse than refusing the edit.
|
|
44
|
+
*
|
|
45
|
+
* `primaryContactId` is deliberately absent: it is a CRM-side judgement about
|
|
46
|
+
* who to talk to, never sourced from the host, so it stays editable on synced
|
|
47
|
+
* rows.
|
|
48
|
+
*/
|
|
49
|
+
const HOST_OWNED_COMPANY_FIELDS = [
|
|
50
|
+
"domain",
|
|
51
|
+
"name",
|
|
52
|
+
"email",
|
|
53
|
+
"phone"
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* True when the record is owned by a host view rather than by the CRM.
|
|
57
|
+
*
|
|
58
|
+
* Deliberately keyed on `sourceRef` and not `entityRole`: `entityRole` is a
|
|
59
|
+
* mapping label that can be absent on a synced row, while `sourceRef` is the
|
|
60
|
+
* identity the sync engine reconciles against and is set for exactly the rows
|
|
61
|
+
* sync will rewrite.
|
|
62
|
+
*/
|
|
63
|
+
function isHostOwned(record) {
|
|
64
|
+
return Boolean(record.sourceRef);
|
|
65
|
+
}
|
|
66
|
+
function rejectedFields(record, patch, owned) {
|
|
67
|
+
if (!isHostOwned(record)) return [];
|
|
68
|
+
return owned.filter((field) => patch[field] !== void 0);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Host-owned contact fields this patch would change, or `[]` when the patch is
|
|
72
|
+
* allowed. Callers turn a non-empty result into a 400 naming the fields.
|
|
73
|
+
*/
|
|
74
|
+
function rejectedContactFields(contact, patch) {
|
|
75
|
+
return rejectedFields(contact, patch, HOST_OWNED_CONTACT_FIELDS);
|
|
76
|
+
}
|
|
77
|
+
/** Host-owned company fields this patch would change, or `[]`. */
|
|
78
|
+
function rejectedCompanyFields(company, patch) {
|
|
79
|
+
return rejectedFields(company, patch, HOST_OWNED_COMPANY_FIELDS);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The message shown when a write is refused. Names the fields and says where
|
|
83
|
+
* they come from, so the reason is actionable rather than a bare "forbidden".
|
|
84
|
+
*/
|
|
85
|
+
function hostOwnedFieldMessage(fields) {
|
|
86
|
+
return `The ${fields.join(", ")} ${fields.length > 1 ? "fields are" : "field is"} synced from your app and cannot be edited here. Change it in your app and it will update on the next sync.`;
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
11
89
|
//#region src/slug.ts
|
|
12
90
|
/**
|
|
13
91
|
* The one `slugify`.
|
|
@@ -180,8 +258,10 @@ exports.explainEntitiesConfig = require_view_compiler.explainEntitiesConfig;
|
|
|
180
258
|
exports.fanOutJoins = require_entity_config.fanOutJoins;
|
|
181
259
|
exports.filterSchema = require_entity_config.filterSchema;
|
|
182
260
|
exports.hasRichMeta = require_schema_meta.hasRichMeta;
|
|
261
|
+
exports.hostOwnedFieldMessage = hostOwnedFieldMessage;
|
|
183
262
|
exports.identityRefs = require_projection.identityRefs;
|
|
184
263
|
exports.isClosedStageType = require_types.isClosedStageType;
|
|
264
|
+
exports.isHostOwned = isHostOwned;
|
|
185
265
|
exports.joinFansOut = require_entity_config.joinFansOut;
|
|
186
266
|
exports.mappingsToEntitiesConfig = require_mappings_config.mappingsToEntitiesConfig;
|
|
187
267
|
exports.matchesCondition = matchesCondition;
|
|
@@ -191,6 +271,8 @@ exports.projectionFields = require_entity_config.projectionFields;
|
|
|
191
271
|
exports.projectionSchema = require_projection.projectionSchema;
|
|
192
272
|
exports.quoteIdent = require_view_compiler.quoteIdent;
|
|
193
273
|
exports.reconcile = require_sync_engine.reconcile;
|
|
274
|
+
exports.rejectedCompanyFields = rejectedCompanyFields;
|
|
275
|
+
exports.rejectedContactFields = rejectedContactFields;
|
|
194
276
|
exports.relationshipSchema = require_entity_config.relationshipSchema;
|
|
195
277
|
exports.relationshipViaSignature = require_mapping_form.relationshipViaSignature;
|
|
196
278
|
exports.relationshipsSchema = require_entity_config.relationshipsSchema;
|