@clivly/core 0.11.0-next.0 → 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-BTAJe1Zj.mjs → entity-config-C0rtu-K_.mjs} +19 -2
- package/dist/{entity-config-CqJknGOn.cjs → entity-config-C2sKAti2.cjs} +19 -2
- package/dist/{entity-config-Ddgukq_E.d.cts → entity-config-OhC4Otkz.d.cts} +3 -1
- package/dist/{entity-config-Ddgukq_E.d.mts → entity-config-OhC4Otkz.d.mts} +3 -1
- 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 +9 -7
- package/dist/entity-heuristics.d.cts +21 -21
- package/dist/entity-heuristics.d.mts +21 -21
- package/dist/entity-heuristics.mjs +9 -7
- 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 +96 -33
- package/dist/types.d.mts +96 -33
- package/dist/view-compiler.d.cts +10 -11
- package/dist/view-compiler.d.mts +10 -11
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,16 +1,83 @@
|
|
|
1
|
-
import { Activity, ActivityType, Company, Contact, ContactFilters, ContactStatus, CreateActivityInput, CreateCompanyInput, CreateContactInput, CreateDealInput, CreateTaskInput, CrmRole, Deal, DealStage, Note, OPEN_STAGE_TYPE, PipelineConfig, PipelineKind, PipelineStageConfig, RecordSource, StageType, Task, TaskEntityType, TaskFilters, TaskPriority, TaskStatus, UpdateContactInput, UpdateDealInput, UpdateTaskInput, ValueInterval, isClosedStageType } from "./types.mjs";
|
|
1
|
+
import { Activity, ActivityType, Company, CompanyFilters, Contact, ContactFilters, ContactStatus, CreateActivityInput, CreateCompanyInput, CreateContactInput, CreateDealInput, CreateTaskInput, CrmRole, Deal, DealStage, Note, OPEN_STAGE_TYPE, PipelineConfig, PipelineKind, PipelineStageConfig, RecordSource, StageType, Task, TaskEntityType, TaskFilters, TaskPriority, TaskStatus, UpdateCompanyInput, UpdateContactInput, UpdateDealInput, UpdateTaskInput, ValueInterval, isClosedStageType } from "./types.mjs";
|
|
2
2
|
import { CRMAdapter } from "./adapter.mjs";
|
|
3
3
|
import { ClivlyAuthAdapter, ClivlyUser, CrmMembership, MembershipResolver, authCustom } from "./auth-adapter.mjs";
|
|
4
|
-
import { A as relationshipsSchema, B as identityRefs, D as missingRequiredFields, E as filterSchema, F as ProjectionFieldBinding, I as ProjectionIdentity, L as ProjectionJoin, M as validateEntitiesConfig, N as BASE_REF, O as projectionFields, P as PROJECTION_KEY_PATTERN, R as ProjectionMapping, S as RelationshipsMap, T as entitiesConfigSchema, V as projectionSchema, _ as MATERIALIZING_CONCEPTS, a as ClivlyEntitiesConfig, b as RelationshipSpec, d as CrmConcept, g as FilterValue, h as FilterExpr, i as ClivlyConfigError, j as requiredFieldsFor, k as relationshipSchema, l as ConfigValidationError, m as DiscoveredSchemaTable, n as CRM_CONCEPTS, p as DiscoveredColumnMeta, s as ClivlyEntityConfig, t as CANONICAL_FIELDS, u as ConfigValidationResult, v as MaterializingConcept, w as defineClivlyConfig, x as RelationshipVia, y as REQUIRED_FIELDS, z as ProjectionRef } from "./entity-config-
|
|
4
|
+
import { A as relationshipsSchema, B as identityRefs, D as missingRequiredFields, E as filterSchema, F as ProjectionFieldBinding, I as ProjectionIdentity, L as ProjectionJoin, M as validateEntitiesConfig, N as BASE_REF, O as projectionFields, P as PROJECTION_KEY_PATTERN, R as ProjectionMapping, S as RelationshipsMap, T as entitiesConfigSchema, V as projectionSchema, _ as MATERIALIZING_CONCEPTS, a as ClivlyEntitiesConfig, b as RelationshipSpec, d as CrmConcept, g as FilterValue, h as FilterExpr, i as ClivlyConfigError, j as requiredFieldsFor, k as relationshipSchema, l as ConfigValidationError, m as DiscoveredSchemaTable, n as CRM_CONCEPTS, p as DiscoveredColumnMeta, s as ClivlyEntityConfig, t as CANONICAL_FIELDS, u as ConfigValidationResult, v as MaterializingConcept, w as defineClivlyConfig, x as RelationshipVia, y as REQUIRED_FIELDS, z as ProjectionRef } from "./entity-config-OhC4Otkz.mjs";
|
|
5
5
|
import { ConnectionLiveness, IntegrationFacts, IntegrationState, IntegrationStatus, IntegrationStep, NextAction, StepId, StepProblem, StepState } from "./integration-state.mjs";
|
|
6
6
|
import { RelationshipCandidate, buildFilterFromDiscriminator, buildRelationships, relationshipViaSignature } from "./mapping-form.mjs";
|
|
7
7
|
import { EntityMappingRow, mappingsToEntitiesConfig } from "./mappings-config.mjs";
|
|
8
8
|
import { CompileOptions, CompiledView, DEFAULT_VIEW_PREFIX, ExplainResult, compileEntityView, compileEntityViews, explainEntitiesConfig } from "./view-compiler.mjs";
|
|
9
9
|
import { EntitySyncResult, MirrorRecord, PersistAction, SourceRow, SyncAction, SyncResult, SyncStore, reconcile, runSync } from "./sync-engine.mjs";
|
|
10
|
+
//#region src/host-owned-fields.d.ts
|
|
11
|
+
/**
|
|
12
|
+
* Which fields a CRM record lets a user edit.
|
|
13
|
+
*
|
|
14
|
+
* A record synced from the host app carries a `sourceRef`. Its identity fields
|
|
15
|
+
* are rewritten from the host view on every sync run, so an edit to one would
|
|
16
|
+
* be silently reverted minutes later — the user sees their change accepted,
|
|
17
|
+
* then gone, with nothing explaining why. That is worse than refusing it.
|
|
18
|
+
*
|
|
19
|
+
* So host-owned fields are rejected at the API, not merely disabled in the UI:
|
|
20
|
+
* the UI is not the security boundary, and the SDK and any future public API
|
|
21
|
+
* reach the same routers.
|
|
22
|
+
*
|
|
23
|
+
* Records created inside the CRM have no `sourceRef` and are fully editable —
|
|
24
|
+
* nothing else owns them.
|
|
25
|
+
*
|
|
26
|
+
* This is the cheap half of a capability matrix. It answers "may a user write
|
|
27
|
+
* this?" but not "may the sync engine write this?", which stays implicit
|
|
28
|
+
* because sync bypasses these routers entirely. An override model (the
|
|
29
|
+
* `stageOverrideAt` pattern on `crm_deals`) can replace this later without
|
|
30
|
+
* changing callers.
|
|
31
|
+
*/
|
|
32
|
+
/** Contact fields the host view owns when the row is synced. */
|
|
33
|
+
declare const HOST_OWNED_CONTACT_FIELDS: readonly ["email", "name"];
|
|
34
|
+
/**
|
|
35
|
+
* Company fields the host view owns when the row is synced.
|
|
36
|
+
*
|
|
37
|
+
* `email` and `phone` joined this list in the same change that made them
|
|
38
|
+
* mappable (migration 0048). They are not identity fields, but ownership here
|
|
39
|
+
* follows what sync rewrites, not what feels identity-like: both flow from the
|
|
40
|
+
* host view on every run, exactly as `email` does for contacts above. Widening
|
|
41
|
+
* `CANONICAL_FIELDS.company` without widening this list is the specific bug
|
|
42
|
+
* this module's doc comment calls worse than refusing the edit.
|
|
43
|
+
*
|
|
44
|
+
* `primaryContactId` is deliberately absent: it is a CRM-side judgement about
|
|
45
|
+
* who to talk to, never sourced from the host, so it stays editable on synced
|
|
46
|
+
* rows.
|
|
47
|
+
*/
|
|
48
|
+
declare const HOST_OWNED_COMPANY_FIELDS: readonly ["domain", "name", "email", "phone"];
|
|
49
|
+
type HostOwnedContactField = (typeof HOST_OWNED_CONTACT_FIELDS)[number];
|
|
50
|
+
type HostOwnedCompanyField = (typeof HOST_OWNED_COMPANY_FIELDS)[number];
|
|
51
|
+
/** The subset of a record this module needs to make its decision. */
|
|
52
|
+
interface SourcedRecord {
|
|
53
|
+
sourceRef?: string | null;
|
|
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
|
+
export declare function isHostOwned(record: SourcedRecord): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Host-owned contact fields this patch would change, or `[]` when the patch is
|
|
66
|
+
* allowed. Callers turn a non-empty result into a 400 naming the fields.
|
|
67
|
+
*/
|
|
68
|
+
export declare function rejectedContactFields(contact: SourcedRecord, patch: Readonly<Record<string, unknown>>): HostOwnedContactField[];
|
|
69
|
+
/** Host-owned company fields this patch would change, or `[]`. */
|
|
70
|
+
export declare function rejectedCompanyFields(company: SourcedRecord, patch: Readonly<Record<string, unknown>>): HostOwnedCompanyField[];
|
|
71
|
+
/**
|
|
72
|
+
* The message shown when a write is refused. Names the fields and says where
|
|
73
|
+
* they come from, so the reason is actionable rather than a bare "forbidden".
|
|
74
|
+
*/
|
|
75
|
+
export declare function hostOwnedFieldMessage(fields: readonly string[]): string;
|
|
76
|
+
//#endregion
|
|
10
77
|
//#region src/projection-cardinality.d.ts
|
|
11
|
-
declare function joinFansOut(join: ProjectionJoin, joinTable: DiscoveredSchemaTable): boolean;
|
|
78
|
+
export declare function joinFansOut(join: ProjectionJoin, joinTable: DiscoveredSchemaTable): boolean;
|
|
12
79
|
/** Every join in the projection that can multiply rows. */
|
|
13
|
-
declare function fanOutJoins(projection: ProjectionMapping, tablesByName: Map<string, DiscoveredSchemaTable>): ProjectionJoin[];
|
|
80
|
+
export declare function fanOutJoins(projection: ProjectionMapping, tablesByName: Map<string, DiscoveredSchemaTable>): ProjectionJoin[];
|
|
14
81
|
//#endregion
|
|
15
82
|
//#region src/projection-sql.d.ts
|
|
16
83
|
/**
|
|
@@ -24,7 +91,7 @@ declare function fanOutJoins(projection: ProjectionMapping, tablesByName: Map<st
|
|
|
24
91
|
* deterministic and injection-safe.
|
|
25
92
|
*/
|
|
26
93
|
/** Quote a single identifier part, escaping embedded double-quotes. */
|
|
27
|
-
declare function quoteIdent(name: string): string;
|
|
94
|
+
export declare function quoteIdent(name: string): string;
|
|
28
95
|
/**
|
|
29
96
|
* The identity expression. Composite identities concatenate their parts with
|
|
30
97
|
* `::`; validation guarantees every part is NOT NULL and non-text, which is
|
|
@@ -35,14 +102,14 @@ declare function quoteIdent(name: string): string;
|
|
|
35
102
|
* also orders and keyset-paginates by it. Sharing one definition is what keeps
|
|
36
103
|
* a pushed row's `id` identical to the one the view would have produced.
|
|
37
104
|
*/
|
|
38
|
-
declare function compileProjectionIdentity(projection: ProjectionMapping, basePkColumn: string): string;
|
|
39
|
-
declare function compileProjectionSelect(projection: ProjectionMapping, basePkColumn: string): {
|
|
105
|
+
export declare function compileProjectionIdentity(projection: ProjectionMapping, basePkColumn: string): string;
|
|
106
|
+
export declare function compileProjectionSelect(projection: ProjectionMapping, basePkColumn: string): {
|
|
40
107
|
columns: string[];
|
|
41
108
|
selectItems: string[];
|
|
42
109
|
};
|
|
43
|
-
declare function compileProjectionJoins(projection: ProjectionMapping): string[];
|
|
110
|
+
export declare function compileProjectionJoins(projection: ProjectionMapping): string[];
|
|
44
111
|
/** `FROM <baseTable> AS "base"` — the alias every ref resolves against. */
|
|
45
|
-
declare function compileProjectionFrom(projection: ProjectionMapping): string;
|
|
112
|
+
export declare function compileProjectionFrom(projection: ProjectionMapping): string;
|
|
46
113
|
/**
|
|
47
114
|
* Hard ceiling on preview rows, regardless of what a caller asks for.
|
|
48
115
|
*
|
|
@@ -50,7 +117,7 @@ declare function compileProjectionFrom(projection: ProjectionMapping): string;
|
|
|
50
117
|
* as often as they like, so the cap belongs beside the query rather than in
|
|
51
118
|
* whichever caller happens to be passing a limit today.
|
|
52
119
|
*/
|
|
53
|
-
declare const PREVIEW_MAX_ROWS = 50;
|
|
120
|
+
export declare const PREVIEW_MAX_ROWS = 50;
|
|
54
121
|
/**
|
|
55
122
|
* One SELECT reading a few rows through an UNSAVED projection, for the derived
|
|
56
123
|
* object builder's preview.
|
|
@@ -66,7 +133,7 @@ declare const PREVIEW_MAX_ROWS = 50;
|
|
|
66
133
|
* reads `row[token]`; a preview is read by a person, in a table whose headers
|
|
67
134
|
* are the field names they just typed.
|
|
68
135
|
*/
|
|
69
|
-
declare function compileProjectionPreview(projection: ProjectionMapping, limit: number): string;
|
|
136
|
+
export declare function compileProjectionPreview(projection: ProjectionMapping, limit: number): string;
|
|
70
137
|
//#endregion
|
|
71
138
|
//#region src/projection-validate.d.ts
|
|
72
139
|
/**
|
|
@@ -89,12 +156,12 @@ declare function compileProjectionPreview(projection: ProjectionMapping, limit:
|
|
|
89
156
|
*
|
|
90
157
|
* Rejecting an unresolvable column closes the last two together.
|
|
91
158
|
*/
|
|
92
|
-
declare function validateProjectionFilter(filter: FilterExpr | undefined, projection: ProjectionMapping, schema: DiscoveredSchemaTable[], base: string): ConfigValidationError[];
|
|
159
|
+
export declare function validateProjectionFilter(filter: FilterExpr | undefined, projection: ProjectionMapping, schema: DiscoveredSchemaTable[], base: string): ConfigValidationError[];
|
|
93
160
|
/**
|
|
94
161
|
* Validate a projection against the discovered schema. Returns every error
|
|
95
162
|
* found (not just the first) so a builder UI can show them all at once.
|
|
96
163
|
*/
|
|
97
|
-
declare function validateProjection(projection: ProjectionMapping, schema: DiscoveredSchemaTable[], base: string): ConfigValidationError[];
|
|
164
|
+
export declare function validateProjection(projection: ProjectionMapping, schema: DiscoveredSchemaTable[], base: string): ConfigValidationError[];
|
|
98
165
|
//#endregion
|
|
99
166
|
//#region src/schema-meta.d.ts
|
|
100
167
|
/**
|
|
@@ -105,12 +172,12 @@ declare function validateProjection(projection: ProjectionMapping, schema: Disco
|
|
|
105
172
|
* projection validation fail closed: we cannot prove a join is many-to-one, so
|
|
106
173
|
* we refuse to compile it rather than guess.
|
|
107
174
|
*/
|
|
108
|
-
declare function columnMetaFor(table: DiscoveredSchemaTable, column: string): DiscoveredColumnMeta | undefined;
|
|
175
|
+
export declare function columnMetaFor(table: DiscoveredSchemaTable, column: string): DiscoveredColumnMeta | undefined;
|
|
109
176
|
/**
|
|
110
177
|
* Every primary-key column. More than one entry means a composite PK, which is
|
|
111
178
|
* why `base_pk` identity is rejected for such tables.
|
|
112
179
|
*/
|
|
113
|
-
declare function primaryKeyColumns(table: DiscoveredSchemaTable): string[];
|
|
180
|
+
export declare function primaryKeyColumns(table: DiscoveredSchemaTable): string[];
|
|
114
181
|
/**
|
|
115
182
|
* Do `columns` contain every column of at least one unique key on `table`?
|
|
116
183
|
*
|
|
@@ -118,7 +185,7 @@ declare function primaryKeyColumns(table: DiscoveredSchemaTable): string[];
|
|
|
118
185
|
* joined table matches at most one row per base row; one that does not can
|
|
119
186
|
* match many.
|
|
120
187
|
*/
|
|
121
|
-
declare function coversUniqueKey(table: DiscoveredSchemaTable, columns: string[]): boolean;
|
|
188
|
+
export declare function coversUniqueKey(table: DiscoveredSchemaTable, columns: string[]): boolean;
|
|
122
189
|
/**
|
|
123
190
|
* A discovered table whose enrichment metadata is known to be present.
|
|
124
191
|
*
|
|
@@ -142,7 +209,7 @@ type RichMetaTable = DiscoveredSchemaTable & {
|
|
|
142
209
|
* The invariant is unchanged: this reports whether the metadata is *known*,
|
|
143
210
|
* never whether the table has keys. Absent metadata stays UNKNOWN.
|
|
144
211
|
*/
|
|
145
|
-
declare function hasRichMeta(table: DiscoveredSchemaTable): table is RichMetaTable;
|
|
212
|
+
export declare function hasRichMeta(table: DiscoveredSchemaTable): table is RichMetaTable;
|
|
146
213
|
//#endregion
|
|
147
214
|
//#region src/slug.d.ts
|
|
148
215
|
/**
|
|
@@ -171,7 +238,7 @@ declare function hasRichMeta(table: DiscoveredSchemaTable): table is RichMetaTab
|
|
|
171
238
|
* `"2024-invoices"` for `"2024 Invoices"`. Callers that need an
|
|
172
239
|
* acceptance-guaranteed identifier want `toObjectTypeSlug`.
|
|
173
240
|
*/
|
|
174
|
-
declare function slugify(value: string): string;
|
|
241
|
+
export declare function slugify(value: string): string;
|
|
175
242
|
/**
|
|
176
243
|
* A slug the server will accept, derived from a display name.
|
|
177
244
|
*
|
|
@@ -193,7 +260,7 @@ declare function slugify(value: string): string;
|
|
|
193
260
|
* decides whether that is "keep typing" or an error, since only it knows
|
|
194
261
|
* whether the field is still being edited.
|
|
195
262
|
*/
|
|
196
|
-
declare function toObjectTypeSlug(displayName: string): string;
|
|
263
|
+
export declare function toObjectTypeSlug(displayName: string): string;
|
|
197
264
|
//#endregion
|
|
198
265
|
//#region src/stage-rules.d.ts
|
|
199
266
|
type ConditionOp = "is_empty" | "is_not_empty" | "equals" | "not_equals" | "greater_than" | "less_than" | "before" | "after";
|
|
@@ -214,7 +281,7 @@ interface EvaluableRule {
|
|
|
214
281
|
* rule referencing a dropped column must fail safe, because treating the field
|
|
215
282
|
* as null would make `is_empty` match every deal.
|
|
216
283
|
*/
|
|
217
|
-
declare function matchesCondition(condition: Condition, fields: Record<string, string | null>, mappedFields: Set<string>): boolean;
|
|
284
|
+
export declare function matchesCondition(condition: Condition, fields: Record<string, string | null>, mappedFields: Set<string>): boolean;
|
|
218
285
|
/**
|
|
219
286
|
* The id of the first rule whose conditions all hold, or null when none do.
|
|
220
287
|
*
|
|
@@ -229,6 +296,6 @@ declare function matchesCondition(condition: Condition, fields: Record<string, s
|
|
|
229
296
|
* vacuously AND to true and capture every deal, which is the opposite of what
|
|
230
297
|
* a half-written rule should do.
|
|
231
298
|
*/
|
|
232
|
-
declare function evaluateStage(rules: EvaluableRule[], fields: Record<string, string | null>, mappedFields: Set<string>): string | null;
|
|
299
|
+
export declare function evaluateStage(rules: EvaluableRule[], fields: Record<string, string | null>, mappedFields: Set<string>): string | null;
|
|
233
300
|
//#endregion
|
|
234
|
-
export { type Activity, type ActivityType, BASE_REF, CANONICAL_FIELDS, type CRMAdapter, CRM_CONCEPTS, type ClivlyAuthAdapter, ClivlyConfigError, type ClivlyEntitiesConfig, type ClivlyEntityConfig, type ClivlyUser, type Company, type CompileOptions, type CompiledView, type Condition, type ConditionOp, type ConfigValidationError, type ConfigValidationResult, type ConnectionLiveness, type Contact, type ContactFilters, type ContactStatus, type CreateActivityInput, type CreateCompanyInput, type CreateContactInput, type CreateDealInput, type CreateTaskInput, type CrmConcept, type CrmMembership, type CrmRole, DEFAULT_VIEW_PREFIX, type Deal, type DealStage, type DiscoveredColumnMeta, type DiscoveredSchemaTable, type EntityMappingRow, type EntitySyncResult, type EvaluableRule, type ExplainResult, type FilterExpr, type FilterValue, type IntegrationFacts, type IntegrationState, type IntegrationStatus, type IntegrationStep, MATERIALIZING_CONCEPTS, type MaterializingConcept, type MembershipResolver, type MirrorRecord, type NextAction, type Note, OPEN_STAGE_TYPE,
|
|
301
|
+
export { type Activity, type ActivityType, BASE_REF, CANONICAL_FIELDS, type CRMAdapter, CRM_CONCEPTS, type ClivlyAuthAdapter, ClivlyConfigError, type ClivlyEntitiesConfig, type ClivlyEntityConfig, type ClivlyUser, type Company, type CompanyFilters, type CompileOptions, type CompiledView, type Condition, type ConditionOp, type ConfigValidationError, type ConfigValidationResult, type ConnectionLiveness, type Contact, type ContactFilters, type ContactStatus, type CreateActivityInput, type CreateCompanyInput, type CreateContactInput, type CreateDealInput, type CreateTaskInput, type CrmConcept, type CrmMembership, type CrmRole, DEFAULT_VIEW_PREFIX, type Deal, type DealStage, type DiscoveredColumnMeta, type DiscoveredSchemaTable, type EntityMappingRow, type EntitySyncResult, type EvaluableRule, type ExplainResult, type FilterExpr, type FilterValue, type HostOwnedCompanyField, type HostOwnedContactField, type IntegrationFacts, type IntegrationState, type IntegrationStatus, type IntegrationStep, MATERIALIZING_CONCEPTS, type MaterializingConcept, type MembershipResolver, type MirrorRecord, type NextAction, type Note, OPEN_STAGE_TYPE, PROJECTION_KEY_PATTERN, type PersistAction, type PipelineConfig, type PipelineKind, type PipelineStageConfig, type ProjectionFieldBinding, type ProjectionIdentity, type ProjectionJoin, type ProjectionMapping, type ProjectionRef, REQUIRED_FIELDS, type RecordSource, type RelationshipCandidate, type RelationshipSpec, type RelationshipVia, type RelationshipsMap, type SourceRow, type SourcedRecord, type StageType, type StepId, type StepProblem, type StepState, type SyncAction, type SyncResult, type SyncStore, type Task, type TaskEntityType, type TaskFilters, type TaskPriority, type TaskStatus, type UpdateCompanyInput, type UpdateContactInput, type UpdateDealInput, type UpdateTaskInput, type ValueInterval, authCustom, buildFilterFromDiscriminator, buildRelationships, compileEntityView, compileEntityViews, defineClivlyConfig, entitiesConfigSchema, explainEntitiesConfig, filterSchema, identityRefs, isClosedStageType, mappingsToEntitiesConfig, missingRequiredFields, projectionFields, projectionSchema, reconcile, relationshipSchema, relationshipViaSignature, relationshipsSchema, requiredFieldsFor, runSync, validateEntitiesConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,90 @@
|
|
|
1
1
|
import { authCustom } from "./auth-adapter.mjs";
|
|
2
2
|
import { i as projectionSchema, n as PROJECTION_KEY_PATTERN, r as identityRefs, t as BASE_REF } from "./projection-SCNrLJMV.mjs";
|
|
3
3
|
import { i as primaryKeyColumns, n as coversUniqueKey, r as hasRichMeta, t as columnMetaFor } from "./schema-meta-Ac7938mT.mjs";
|
|
4
|
-
import { _ as validateProjection, a as MATERIALIZING_CONCEPTS, b as joinFansOut, c as defineClivlyConfig, d as missingRequiredFields, f as projectionFields, g as validateEntitiesConfig, h as requiredFieldsFor, i as ClivlyConfigError, l as entitiesConfigSchema, m as relationshipsSchema, n as CRM_CONCEPTS, o as REQUIRED_FIELDS, p as relationshipSchema, t as CANONICAL_FIELDS, u as filterSchema, v as validateProjectionFilter, y as fanOutJoins } from "./entity-config-
|
|
4
|
+
import { _ as validateProjection, a as MATERIALIZING_CONCEPTS, b as joinFansOut, c as defineClivlyConfig, d as missingRequiredFields, f as projectionFields, g as validateEntitiesConfig, h as requiredFieldsFor, i as ClivlyConfigError, l as entitiesConfigSchema, m as relationshipsSchema, n as CRM_CONCEPTS, o as REQUIRED_FIELDS, p as relationshipSchema, t as CANONICAL_FIELDS, u as filterSchema, v as validateProjectionFilter, y as fanOutJoins } from "./entity-config-C0rtu-K_.mjs";
|
|
5
5
|
import { buildFilterFromDiscriminator, buildRelationships, relationshipViaSignature } from "./mapping-form.mjs";
|
|
6
6
|
import { mappingsToEntitiesConfig } from "./mappings-config.mjs";
|
|
7
7
|
import { c as compileProjectionIdentity, d as compileProjectionSelect, f as quoteIdent, i as explainEntitiesConfig, l as compileProjectionJoins, n as compileEntityView, o as PREVIEW_MAX_ROWS, r as compileEntityViews, s as compileProjectionFrom, t as DEFAULT_VIEW_PREFIX, u as compileProjectionPreview } from "./view-compiler-CLvZ0wJW.mjs";
|
|
8
8
|
import { reconcile, runSync } from "./sync-engine.mjs";
|
|
9
9
|
import { OPEN_STAGE_TYPE, isClosedStageType } from "./types.mjs";
|
|
10
|
+
//#region src/host-owned-fields.ts
|
|
11
|
+
/**
|
|
12
|
+
* Which fields a CRM record lets a user edit.
|
|
13
|
+
*
|
|
14
|
+
* A record synced from the host app carries a `sourceRef`. Its identity fields
|
|
15
|
+
* are rewritten from the host view on every sync run, so an edit to one would
|
|
16
|
+
* be silently reverted minutes later — the user sees their change accepted,
|
|
17
|
+
* then gone, with nothing explaining why. That is worse than refusing it.
|
|
18
|
+
*
|
|
19
|
+
* So host-owned fields are rejected at the API, not merely disabled in the UI:
|
|
20
|
+
* the UI is not the security boundary, and the SDK and any future public API
|
|
21
|
+
* reach the same routers.
|
|
22
|
+
*
|
|
23
|
+
* Records created inside the CRM have no `sourceRef` and are fully editable —
|
|
24
|
+
* nothing else owns them.
|
|
25
|
+
*
|
|
26
|
+
* This is the cheap half of a capability matrix. It answers "may a user write
|
|
27
|
+
* this?" but not "may the sync engine write this?", which stays implicit
|
|
28
|
+
* because sync bypasses these routers entirely. An override model (the
|
|
29
|
+
* `stageOverrideAt` pattern on `crm_deals`) can replace this later without
|
|
30
|
+
* changing callers.
|
|
31
|
+
*/
|
|
32
|
+
/** Contact fields the host view owns when the row is synced. */
|
|
33
|
+
const HOST_OWNED_CONTACT_FIELDS = ["email", "name"];
|
|
34
|
+
/**
|
|
35
|
+
* Company fields the host view owns when the row is synced.
|
|
36
|
+
*
|
|
37
|
+
* `email` and `phone` joined this list in the same change that made them
|
|
38
|
+
* mappable (migration 0048). They are not identity fields, but ownership here
|
|
39
|
+
* follows what sync rewrites, not what feels identity-like: both flow from the
|
|
40
|
+
* host view on every run, exactly as `email` does for contacts above. Widening
|
|
41
|
+
* `CANONICAL_FIELDS.company` without widening this list is the specific bug
|
|
42
|
+
* this module's doc comment calls worse than refusing the edit.
|
|
43
|
+
*
|
|
44
|
+
* `primaryContactId` is deliberately absent: it is a CRM-side judgement about
|
|
45
|
+
* who to talk to, never sourced from the host, so it stays editable on synced
|
|
46
|
+
* rows.
|
|
47
|
+
*/
|
|
48
|
+
const HOST_OWNED_COMPANY_FIELDS = [
|
|
49
|
+
"domain",
|
|
50
|
+
"name",
|
|
51
|
+
"email",
|
|
52
|
+
"phone"
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* True when the record is owned by a host view rather than by the CRM.
|
|
56
|
+
*
|
|
57
|
+
* Deliberately keyed on `sourceRef` and not `entityRole`: `entityRole` is a
|
|
58
|
+
* mapping label that can be absent on a synced row, while `sourceRef` is the
|
|
59
|
+
* identity the sync engine reconciles against and is set for exactly the rows
|
|
60
|
+
* sync will rewrite.
|
|
61
|
+
*/
|
|
62
|
+
function isHostOwned(record) {
|
|
63
|
+
return Boolean(record.sourceRef);
|
|
64
|
+
}
|
|
65
|
+
function rejectedFields(record, patch, owned) {
|
|
66
|
+
if (!isHostOwned(record)) return [];
|
|
67
|
+
return owned.filter((field) => patch[field] !== void 0);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Host-owned contact fields this patch would change, or `[]` when the patch is
|
|
71
|
+
* allowed. Callers turn a non-empty result into a 400 naming the fields.
|
|
72
|
+
*/
|
|
73
|
+
function rejectedContactFields(contact, patch) {
|
|
74
|
+
return rejectedFields(contact, patch, HOST_OWNED_CONTACT_FIELDS);
|
|
75
|
+
}
|
|
76
|
+
/** Host-owned company fields this patch would change, or `[]`. */
|
|
77
|
+
function rejectedCompanyFields(company, patch) {
|
|
78
|
+
return rejectedFields(company, patch, HOST_OWNED_COMPANY_FIELDS);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The message shown when a write is refused. Names the fields and says where
|
|
82
|
+
* they come from, so the reason is actionable rather than a bare "forbidden".
|
|
83
|
+
*/
|
|
84
|
+
function hostOwnedFieldMessage(fields) {
|
|
85
|
+
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.`;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
10
88
|
//#region src/slug.ts
|
|
11
89
|
/**
|
|
12
90
|
* The one `slugify`.
|
|
@@ -150,4 +228,4 @@ function evaluateStage(rules, fields, mappedFields) {
|
|
|
150
228
|
return null;
|
|
151
229
|
}
|
|
152
230
|
//#endregion
|
|
153
|
-
export { BASE_REF, CANONICAL_FIELDS, CRM_CONCEPTS, ClivlyConfigError, DEFAULT_VIEW_PREFIX, MATERIALIZING_CONCEPTS, OPEN_STAGE_TYPE, PREVIEW_MAX_ROWS, PROJECTION_KEY_PATTERN, REQUIRED_FIELDS, authCustom, buildFilterFromDiscriminator, buildRelationships, columnMetaFor, compileEntityView, compileEntityViews, compileProjectionFrom, compileProjectionIdentity, compileProjectionJoins, compileProjectionPreview, compileProjectionSelect, coversUniqueKey, defineClivlyConfig, entitiesConfigSchema, evaluateStage, explainEntitiesConfig, fanOutJoins, filterSchema, hasRichMeta, identityRefs, isClosedStageType, joinFansOut, mappingsToEntitiesConfig, matchesCondition, missingRequiredFields, primaryKeyColumns, projectionFields, projectionSchema, quoteIdent, reconcile, relationshipSchema, relationshipViaSignature, relationshipsSchema, requiredFieldsFor, runSync, slugify, toObjectTypeSlug, validateEntitiesConfig, validateProjection, validateProjectionFilter };
|
|
231
|
+
export { BASE_REF, CANONICAL_FIELDS, CRM_CONCEPTS, ClivlyConfigError, DEFAULT_VIEW_PREFIX, MATERIALIZING_CONCEPTS, OPEN_STAGE_TYPE, PREVIEW_MAX_ROWS, PROJECTION_KEY_PATTERN, REQUIRED_FIELDS, authCustom, buildFilterFromDiscriminator, buildRelationships, columnMetaFor, compileEntityView, compileEntityViews, compileProjectionFrom, compileProjectionIdentity, compileProjectionJoins, compileProjectionPreview, compileProjectionSelect, coversUniqueKey, defineClivlyConfig, entitiesConfigSchema, evaluateStage, explainEntitiesConfig, fanOutJoins, filterSchema, hasRichMeta, hostOwnedFieldMessage, identityRefs, isClosedStageType, isHostOwned, joinFansOut, mappingsToEntitiesConfig, matchesCondition, missingRequiredFields, primaryKeyColumns, projectionFields, projectionSchema, quoteIdent, reconcile, rejectedCompanyFields, rejectedContactFields, relationshipSchema, relationshipViaSignature, relationshipsSchema, requiredFieldsFor, runSync, slugify, toObjectTypeSlug, validateEntitiesConfig, validateProjection, validateProjectionFilter };
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
//#region src/integration-state.d.ts
|
|
2
|
-
declare const INTEGRATION_STEPS: readonly ["credential", "application", "schema", "mapping", "trigger", "sync", "widget"];
|
|
3
|
-
type StepId = (typeof INTEGRATION_STEPS)[number];
|
|
2
|
+
export declare const INTEGRATION_STEPS: readonly ["credential", "application", "schema", "mapping", "trigger", "sync", "widget"];
|
|
3
|
+
export type StepId = (typeof INTEGRATION_STEPS)[number];
|
|
4
4
|
/** `blocked` means "prerequisite unmet", never "broken" — see C-19. */
|
|
5
|
-
type StepState = "done" | "active" | "blocked" | "failed" | "skipped";
|
|
6
|
-
type IntegrationStatus = "not_configured" | "sdk_installed" | "awaiting_connection" | "connected" | "schema_discovered" | "mapping_required" | "trigger_required" | "ready_to_sync" | "syncing" | "healthy" | "warning" | "error" |
|
|
5
|
+
export type StepState = "done" | "active" | "blocked" | "failed" | "skipped";
|
|
6
|
+
export type IntegrationStatus = "not_configured" | "sdk_installed" | "awaiting_connection" | "connected" | "schema_discovered" | "mapping_required" | "trigger_required" | "ready_to_sync" | "syncing" | "healthy" | "warning" | "error" |
|
|
7
7
|
/**
|
|
8
8
|
* @deprecated No longer derived. Liveness is its own dimension — read
|
|
9
9
|
* `ConnectionHealth` from `deriveLiveness`. Setup progress does not move
|
|
10
10
|
* backwards just because an app stopped running.
|
|
11
11
|
*/
|
|
12
12
|
"disconnected";
|
|
13
|
-
declare const INTEGRATION_STEP_LABELS: Record<StepId, string>;
|
|
13
|
+
export declare const INTEGRATION_STEP_LABELS: Record<StepId, string>;
|
|
14
14
|
/** Each step's prerequisites. Ordering is enforced by a test, not convention. */
|
|
15
|
-
declare const STEP_PREREQUISITES: Record<StepId, readonly StepId[]>;
|
|
16
|
-
declare function stepIndex(id: StepId): number;
|
|
17
|
-
interface RunFact {
|
|
15
|
+
export declare const STEP_PREREQUISITES: Record<StepId, readonly StepId[]>;
|
|
16
|
+
export declare function stepIndex(id: StepId): number;
|
|
17
|
+
export interface RunFact {
|
|
18
18
|
at: number;
|
|
19
19
|
message?: string;
|
|
20
20
|
ok: boolean;
|
|
@@ -36,8 +36,8 @@ interface RunFact {
|
|
|
36
36
|
* such a host to `local_dev` would file a production box's faults under local
|
|
37
37
|
* development, where nobody would look for them.
|
|
38
38
|
*/
|
|
39
|
-
type HostEnvironment = "local_dev" | "preview" | "production" | "unknown";
|
|
40
|
-
interface IntegrationFacts {
|
|
39
|
+
export type HostEnvironment = "local_dev" | "preview" | "production" | "unknown";
|
|
40
|
+
export interface IntegrationFacts {
|
|
41
41
|
discoveredTableCount: number;
|
|
42
42
|
/** The environment the app reported on its last heartbeat. */
|
|
43
43
|
environment?: HostEnvironment | null;
|
|
@@ -95,12 +95,12 @@ interface IntegrationFacts {
|
|
|
95
95
|
warnings: string[];
|
|
96
96
|
widgetInstalled: boolean;
|
|
97
97
|
}
|
|
98
|
-
interface StepProblem {
|
|
98
|
+
export interface StepProblem {
|
|
99
99
|
code: string;
|
|
100
100
|
fix: string;
|
|
101
101
|
message: string;
|
|
102
102
|
}
|
|
103
|
-
interface IntegrationStep {
|
|
103
|
+
export interface IntegrationStep {
|
|
104
104
|
blockedBy: StepId | null;
|
|
105
105
|
evidence: string | null;
|
|
106
106
|
id: StepId;
|
|
@@ -108,10 +108,10 @@ interface IntegrationStep {
|
|
|
108
108
|
problem: StepProblem | null;
|
|
109
109
|
state: StepState;
|
|
110
110
|
}
|
|
111
|
-
declare function formatAge(ms: number): string;
|
|
111
|
+
export declare function formatAge(ms: number): string;
|
|
112
112
|
/** The cadence `createClivlySDK` uses when the host app configures none. */
|
|
113
|
-
declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 60000;
|
|
114
|
-
type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
113
|
+
export declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 60000;
|
|
114
|
+
export type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
115
115
|
/**
|
|
116
116
|
* Clivly's own answer to "is this app up", obtained by asking it rather than
|
|
117
117
|
* waiting to be told.
|
|
@@ -121,15 +121,15 @@ type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
|
121
121
|
* that answers `200`. Only silence — a timeout, a refused connection, DNS that
|
|
122
122
|
* does not resolve — means offline.
|
|
123
123
|
*/
|
|
124
|
-
interface ReachabilityProbe {
|
|
124
|
+
export interface ReachabilityProbe {
|
|
125
125
|
/** When Clivly performed the check. Probe results are cached, so this ages. */
|
|
126
126
|
checkedAt: number;
|
|
127
127
|
/** Did anything answer at the other end? */
|
|
128
128
|
reachable: boolean;
|
|
129
129
|
}
|
|
130
130
|
/** Which algorithm decides whether this deployment is up. */
|
|
131
|
-
type PresenceTransport = "websocket" | "http";
|
|
132
|
-
type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
131
|
+
export type PresenceTransport = "websocket" | "http";
|
|
132
|
+
export type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
133
133
|
/**
|
|
134
134
|
* A deployment's connection state as its `PresenceRoom` last persisted it.
|
|
135
135
|
*
|
|
@@ -138,13 +138,13 @@ type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
|
138
138
|
* shown as live for 150 seconds and offline only after ten minutes, which is
|
|
139
139
|
* the whole reason this transport exists.
|
|
140
140
|
*/
|
|
141
|
-
interface DeploymentPresence {
|
|
141
|
+
export interface DeploymentPresence {
|
|
142
142
|
/** Sockets currently accepted in the room. */
|
|
143
143
|
activeInstanceCount: number;
|
|
144
144
|
connectionState: PresenceConnectionState;
|
|
145
145
|
transport: PresenceTransport;
|
|
146
146
|
}
|
|
147
|
-
interface ConnectionLiveness {
|
|
147
|
+
export interface ConnectionLiveness {
|
|
148
148
|
/** `"8s ago"`, or `"No heartbeat yet"` when the app has never reported. */
|
|
149
149
|
ageLabel: string;
|
|
150
150
|
ageMs: number | null;
|
|
@@ -165,30 +165,30 @@ interface ConnectionLiveness {
|
|
|
165
165
|
* negative — falls back to the SDK default rather than producing a window of
|
|
166
166
|
* zero that would call every app offline.
|
|
167
167
|
*/
|
|
168
|
-
declare function livenessWindows(intervalMs: number | null | undefined): {
|
|
168
|
+
export declare function livenessWindows(intervalMs: number | null | undefined): {
|
|
169
169
|
liveMs: number;
|
|
170
170
|
staleMs: number;
|
|
171
171
|
};
|
|
172
|
-
declare function deriveLiveness(facts: IntegrationFacts): ConnectionLiveness;
|
|
172
|
+
export declare function deriveLiveness(facts: IntegrationFacts): ConnectionLiveness;
|
|
173
173
|
/**
|
|
174
174
|
* Walk the ladder once. A step is `blocked` when an earlier step it needs has
|
|
175
175
|
* not been satisfied — a prerequisite statement, not a verdict about this step
|
|
176
176
|
* — and only the first unsatisfied step is `active`, so exactly one root cause
|
|
177
177
|
* ever surfaces.
|
|
178
178
|
*/
|
|
179
|
-
declare function resolveSteps(facts: IntegrationFacts): IntegrationStep[];
|
|
179
|
+
export declare function resolveSteps(facts: IntegrationFacts): IntegrationStep[];
|
|
180
180
|
/**
|
|
181
181
|
* Collapse the ladder to the single status the surfaces switch on. This is the
|
|
182
182
|
* setup dimension only: it answers how far configuration got, never whether the
|
|
183
183
|
* app is up. Pair it with `deriveLiveness` for the second half of the picture.
|
|
184
184
|
*/
|
|
185
|
-
declare function deriveStatus(steps: IntegrationStep[], facts: IntegrationFacts): IntegrationStatus;
|
|
186
|
-
interface NextAction {
|
|
185
|
+
export declare function deriveStatus(steps: IntegrationStep[], facts: IntegrationFacts): IntegrationStatus;
|
|
186
|
+
export interface NextAction {
|
|
187
187
|
command: string | null;
|
|
188
188
|
envFile: string | null;
|
|
189
189
|
label: string;
|
|
190
190
|
}
|
|
191
|
-
interface IntegrationState {
|
|
191
|
+
export interface IntegrationState {
|
|
192
192
|
/**
|
|
193
193
|
* Is the app running right now. Deliberately alongside `status` rather than
|
|
194
194
|
* folded into it: a surface must be able to say "setup reached mapping" and
|
|
@@ -205,14 +205,13 @@ interface IntegrationState {
|
|
|
205
205
|
* dialog prints it too, and it must be the same string as the one the ladder
|
|
206
206
|
* recommends — that pairing is what C-05 broke.
|
|
207
207
|
*/
|
|
208
|
-
declare const INSTALL_COMMAND = "npx clivly init";
|
|
208
|
+
export declare const INSTALL_COMMAND = "npx clivly init";
|
|
209
209
|
/**
|
|
210
210
|
* THE one producer of `next.command`. Six surfaces previously each invented
|
|
211
211
|
* their own "run this next" string, and one of them named a read-only command
|
|
212
212
|
* as the fix for a write problem (C-05). If you need a command for the
|
|
213
213
|
* next-action slot, call this — do not write another one.
|
|
214
214
|
*/
|
|
215
|
-
declare function nextAction(steps: IntegrationStep[], status: IntegrationStatus, liveness: ConnectionLiveness): NextAction | null;
|
|
216
|
-
declare function computeIntegrationState(facts: IntegrationFacts): IntegrationState;
|
|
217
|
-
//#endregion
|
|
218
|
-
export { ConnectionHealth, ConnectionLiveness, DEFAULT_HEARTBEAT_INTERVAL_MS, DeploymentPresence, HostEnvironment, INSTALL_COMMAND, INTEGRATION_STEPS, INTEGRATION_STEP_LABELS, IntegrationFacts, IntegrationState, IntegrationStatus, IntegrationStep, NextAction, PresenceConnectionState, PresenceTransport, ReachabilityProbe, RunFact, STEP_PREREQUISITES, StepId, StepProblem, StepState, computeIntegrationState, deriveLiveness, deriveStatus, formatAge, livenessWindows, nextAction, resolveSteps, stepIndex };
|
|
215
|
+
export declare function nextAction(steps: IntegrationStep[], status: IntegrationStatus, liveness: ConnectionLiveness): NextAction | null;
|
|
216
|
+
export declare function computeIntegrationState(facts: IntegrationFacts): IntegrationState;
|
|
217
|
+
//#endregion
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
//#region src/integration-state.d.ts
|
|
2
|
-
declare const INTEGRATION_STEPS: readonly ["credential", "application", "schema", "mapping", "trigger", "sync", "widget"];
|
|
3
|
-
type StepId = (typeof INTEGRATION_STEPS)[number];
|
|
2
|
+
export declare const INTEGRATION_STEPS: readonly ["credential", "application", "schema", "mapping", "trigger", "sync", "widget"];
|
|
3
|
+
export type StepId = (typeof INTEGRATION_STEPS)[number];
|
|
4
4
|
/** `blocked` means "prerequisite unmet", never "broken" — see C-19. */
|
|
5
|
-
type StepState = "done" | "active" | "blocked" | "failed" | "skipped";
|
|
6
|
-
type IntegrationStatus = "not_configured" | "sdk_installed" | "awaiting_connection" | "connected" | "schema_discovered" | "mapping_required" | "trigger_required" | "ready_to_sync" | "syncing" | "healthy" | "warning" | "error" |
|
|
5
|
+
export type StepState = "done" | "active" | "blocked" | "failed" | "skipped";
|
|
6
|
+
export type IntegrationStatus = "not_configured" | "sdk_installed" | "awaiting_connection" | "connected" | "schema_discovered" | "mapping_required" | "trigger_required" | "ready_to_sync" | "syncing" | "healthy" | "warning" | "error" |
|
|
7
7
|
/**
|
|
8
8
|
* @deprecated No longer derived. Liveness is its own dimension — read
|
|
9
9
|
* `ConnectionHealth` from `deriveLiveness`. Setup progress does not move
|
|
10
10
|
* backwards just because an app stopped running.
|
|
11
11
|
*/
|
|
12
12
|
"disconnected";
|
|
13
|
-
declare const INTEGRATION_STEP_LABELS: Record<StepId, string>;
|
|
13
|
+
export declare const INTEGRATION_STEP_LABELS: Record<StepId, string>;
|
|
14
14
|
/** Each step's prerequisites. Ordering is enforced by a test, not convention. */
|
|
15
|
-
declare const STEP_PREREQUISITES: Record<StepId, readonly StepId[]>;
|
|
16
|
-
declare function stepIndex(id: StepId): number;
|
|
17
|
-
interface RunFact {
|
|
15
|
+
export declare const STEP_PREREQUISITES: Record<StepId, readonly StepId[]>;
|
|
16
|
+
export declare function stepIndex(id: StepId): number;
|
|
17
|
+
export interface RunFact {
|
|
18
18
|
at: number;
|
|
19
19
|
message?: string;
|
|
20
20
|
ok: boolean;
|
|
@@ -36,8 +36,8 @@ interface RunFact {
|
|
|
36
36
|
* such a host to `local_dev` would file a production box's faults under local
|
|
37
37
|
* development, where nobody would look for them.
|
|
38
38
|
*/
|
|
39
|
-
type HostEnvironment = "local_dev" | "preview" | "production" | "unknown";
|
|
40
|
-
interface IntegrationFacts {
|
|
39
|
+
export type HostEnvironment = "local_dev" | "preview" | "production" | "unknown";
|
|
40
|
+
export interface IntegrationFacts {
|
|
41
41
|
discoveredTableCount: number;
|
|
42
42
|
/** The environment the app reported on its last heartbeat. */
|
|
43
43
|
environment?: HostEnvironment | null;
|
|
@@ -95,12 +95,12 @@ interface IntegrationFacts {
|
|
|
95
95
|
warnings: string[];
|
|
96
96
|
widgetInstalled: boolean;
|
|
97
97
|
}
|
|
98
|
-
interface StepProblem {
|
|
98
|
+
export interface StepProblem {
|
|
99
99
|
code: string;
|
|
100
100
|
fix: string;
|
|
101
101
|
message: string;
|
|
102
102
|
}
|
|
103
|
-
interface IntegrationStep {
|
|
103
|
+
export interface IntegrationStep {
|
|
104
104
|
blockedBy: StepId | null;
|
|
105
105
|
evidence: string | null;
|
|
106
106
|
id: StepId;
|
|
@@ -108,10 +108,10 @@ interface IntegrationStep {
|
|
|
108
108
|
problem: StepProblem | null;
|
|
109
109
|
state: StepState;
|
|
110
110
|
}
|
|
111
|
-
declare function formatAge(ms: number): string;
|
|
111
|
+
export declare function formatAge(ms: number): string;
|
|
112
112
|
/** The cadence `createClivlySDK` uses when the host app configures none. */
|
|
113
|
-
declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 60000;
|
|
114
|
-
type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
113
|
+
export declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 60000;
|
|
114
|
+
export type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
115
115
|
/**
|
|
116
116
|
* Clivly's own answer to "is this app up", obtained by asking it rather than
|
|
117
117
|
* waiting to be told.
|
|
@@ -121,15 +121,15 @@ type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
|
121
121
|
* that answers `200`. Only silence — a timeout, a refused connection, DNS that
|
|
122
122
|
* does not resolve — means offline.
|
|
123
123
|
*/
|
|
124
|
-
interface ReachabilityProbe {
|
|
124
|
+
export interface ReachabilityProbe {
|
|
125
125
|
/** When Clivly performed the check. Probe results are cached, so this ages. */
|
|
126
126
|
checkedAt: number;
|
|
127
127
|
/** Did anything answer at the other end? */
|
|
128
128
|
reachable: boolean;
|
|
129
129
|
}
|
|
130
130
|
/** Which algorithm decides whether this deployment is up. */
|
|
131
|
-
type PresenceTransport = "websocket" | "http";
|
|
132
|
-
type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
131
|
+
export type PresenceTransport = "websocket" | "http";
|
|
132
|
+
export type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
133
133
|
/**
|
|
134
134
|
* A deployment's connection state as its `PresenceRoom` last persisted it.
|
|
135
135
|
*
|
|
@@ -138,13 +138,13 @@ type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
|
138
138
|
* shown as live for 150 seconds and offline only after ten minutes, which is
|
|
139
139
|
* the whole reason this transport exists.
|
|
140
140
|
*/
|
|
141
|
-
interface DeploymentPresence {
|
|
141
|
+
export interface DeploymentPresence {
|
|
142
142
|
/** Sockets currently accepted in the room. */
|
|
143
143
|
activeInstanceCount: number;
|
|
144
144
|
connectionState: PresenceConnectionState;
|
|
145
145
|
transport: PresenceTransport;
|
|
146
146
|
}
|
|
147
|
-
interface ConnectionLiveness {
|
|
147
|
+
export interface ConnectionLiveness {
|
|
148
148
|
/** `"8s ago"`, or `"No heartbeat yet"` when the app has never reported. */
|
|
149
149
|
ageLabel: string;
|
|
150
150
|
ageMs: number | null;
|
|
@@ -165,30 +165,30 @@ interface ConnectionLiveness {
|
|
|
165
165
|
* negative — falls back to the SDK default rather than producing a window of
|
|
166
166
|
* zero that would call every app offline.
|
|
167
167
|
*/
|
|
168
|
-
declare function livenessWindows(intervalMs: number | null | undefined): {
|
|
168
|
+
export declare function livenessWindows(intervalMs: number | null | undefined): {
|
|
169
169
|
liveMs: number;
|
|
170
170
|
staleMs: number;
|
|
171
171
|
};
|
|
172
|
-
declare function deriveLiveness(facts: IntegrationFacts): ConnectionLiveness;
|
|
172
|
+
export declare function deriveLiveness(facts: IntegrationFacts): ConnectionLiveness;
|
|
173
173
|
/**
|
|
174
174
|
* Walk the ladder once. A step is `blocked` when an earlier step it needs has
|
|
175
175
|
* not been satisfied — a prerequisite statement, not a verdict about this step
|
|
176
176
|
* — and only the first unsatisfied step is `active`, so exactly one root cause
|
|
177
177
|
* ever surfaces.
|
|
178
178
|
*/
|
|
179
|
-
declare function resolveSteps(facts: IntegrationFacts): IntegrationStep[];
|
|
179
|
+
export declare function resolveSteps(facts: IntegrationFacts): IntegrationStep[];
|
|
180
180
|
/**
|
|
181
181
|
* Collapse the ladder to the single status the surfaces switch on. This is the
|
|
182
182
|
* setup dimension only: it answers how far configuration got, never whether the
|
|
183
183
|
* app is up. Pair it with `deriveLiveness` for the second half of the picture.
|
|
184
184
|
*/
|
|
185
|
-
declare function deriveStatus(steps: IntegrationStep[], facts: IntegrationFacts): IntegrationStatus;
|
|
186
|
-
interface NextAction {
|
|
185
|
+
export declare function deriveStatus(steps: IntegrationStep[], facts: IntegrationFacts): IntegrationStatus;
|
|
186
|
+
export interface NextAction {
|
|
187
187
|
command: string | null;
|
|
188
188
|
envFile: string | null;
|
|
189
189
|
label: string;
|
|
190
190
|
}
|
|
191
|
-
interface IntegrationState {
|
|
191
|
+
export interface IntegrationState {
|
|
192
192
|
/**
|
|
193
193
|
* Is the app running right now. Deliberately alongside `status` rather than
|
|
194
194
|
* folded into it: a surface must be able to say "setup reached mapping" and
|
|
@@ -205,14 +205,13 @@ interface IntegrationState {
|
|
|
205
205
|
* dialog prints it too, and it must be the same string as the one the ladder
|
|
206
206
|
* recommends — that pairing is what C-05 broke.
|
|
207
207
|
*/
|
|
208
|
-
declare const INSTALL_COMMAND = "npx clivly init";
|
|
208
|
+
export declare const INSTALL_COMMAND = "npx clivly init";
|
|
209
209
|
/**
|
|
210
210
|
* THE one producer of `next.command`. Six surfaces previously each invented
|
|
211
211
|
* their own "run this next" string, and one of them named a read-only command
|
|
212
212
|
* as the fix for a write problem (C-05). If you need a command for the
|
|
213
213
|
* next-action slot, call this — do not write another one.
|
|
214
214
|
*/
|
|
215
|
-
declare function nextAction(steps: IntegrationStep[], status: IntegrationStatus, liveness: ConnectionLiveness): NextAction | null;
|
|
216
|
-
declare function computeIntegrationState(facts: IntegrationFacts): IntegrationState;
|
|
217
|
-
//#endregion
|
|
218
|
-
export { ConnectionHealth, ConnectionLiveness, DEFAULT_HEARTBEAT_INTERVAL_MS, DeploymentPresence, HostEnvironment, INSTALL_COMMAND, INTEGRATION_STEPS, INTEGRATION_STEP_LABELS, IntegrationFacts, IntegrationState, IntegrationStatus, IntegrationStep, NextAction, PresenceConnectionState, PresenceTransport, ReachabilityProbe, RunFact, STEP_PREREQUISITES, StepId, StepProblem, StepState, computeIntegrationState, deriveLiveness, deriveStatus, formatAge, livenessWindows, nextAction, resolveSteps, stepIndex };
|
|
215
|
+
export declare function nextAction(steps: IntegrationStep[], status: IntegrationStatus, liveness: ConnectionLiveness): NextAction | null;
|
|
216
|
+
export declare function computeIntegrationState(facts: IntegrationFacts): IntegrationState;
|
|
217
|
+
//#endregion
|