clivly 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +330 -134
  2. package/core-drizzle.cjs +3 -1
  3. package/core-drizzle.d.cts +3 -2
  4. package/core-drizzle.d.mts +3 -2
  5. package/core-drizzle.mjs +2 -2
  6. package/core-entity-config.cjs +1 -1
  7. package/core-entity-config.d.cts +2 -2
  8. package/core-entity-config.d.mts +2 -2
  9. package/core-entity-config.mjs +1 -1
  10. package/core-entity-heuristics.d.cts +3 -2
  11. package/core-entity-heuristics.d.mts +3 -2
  12. package/core-mapping-form.d.cts +1 -1
  13. package/core-mapping-form.d.mts +1 -1
  14. package/core-mappings-config.cjs +1 -1
  15. package/core-mappings-config.d.cts +1 -1
  16. package/core-mappings-config.d.mts +1 -1
  17. package/core-mappings-config.mjs +1 -1
  18. package/core-sync-engine.cjs +1 -1
  19. package/core-sync-engine.d.cts +1 -1
  20. package/core-sync-engine.d.mts +1 -1
  21. package/core-sync-engine.mjs +1 -1
  22. package/core-view-compiler.cjs +1 -1
  23. package/core-view-compiler.d.cts +1 -1
  24. package/core-view-compiler.d.mts +1 -1
  25. package/core-view-compiler.mjs +1 -1
  26. package/core.cjs +21 -5
  27. package/core.d.cts +7 -6
  28. package/core.d.mts +7 -6
  29. package/core.mjs +7 -6
  30. package/drizzle-3kvhkwO7.mjs +110 -0
  31. package/drizzle-BhN5M9zt.d.cts +41 -0
  32. package/drizzle-bfjVzYR6.cjs +127 -0
  33. package/drizzle-kBULBAOa.d.mts +41 -0
  34. package/drizzle.cjs +12 -40
  35. package/drizzle.d.cts +3 -11
  36. package/drizzle.d.mts +3 -11
  37. package/drizzle.mjs +12 -41
  38. package/{entity-config-DoUCXtq5.d.cts → entity-config-C4Yf_fPj.d.cts} +120 -1
  39. package/{entity-config-DoUCXtq5.d.mts → entity-config-C4Yf_fPj.d.mts} +120 -1
  40. package/entity-config-CsLl-ftC.cjs +727 -0
  41. package/entity-config-D3LmzgLb.mjs +612 -0
  42. package/index.cjs +764 -120
  43. package/index.d.cts +12 -0
  44. package/index.d.mts +12 -0
  45. package/index.mjs +765 -121
  46. package/internal-B8ydhsKd.d.cts +73 -0
  47. package/internal-BARjyN4n.cjs +97 -0
  48. package/internal-DMySVbM0.mjs +68 -0
  49. package/internal-MBkNo3bw.d.mts +73 -0
  50. package/internal-drizzle.cjs +3 -1
  51. package/internal-drizzle.d.cts +2 -2
  52. package/internal-drizzle.d.mts +2 -2
  53. package/internal-drizzle.mjs +2 -2
  54. package/internal-entity-config.cjs +1 -1
  55. package/internal-entity-config.d.cts +2 -2
  56. package/internal-entity-config.d.mts +2 -2
  57. package/internal-entity-config.mjs +1 -1
  58. package/internal-entity-heuristics.cjs +28 -8
  59. package/internal-entity-heuristics.d.cts +2 -12
  60. package/internal-entity-heuristics.d.mts +2 -12
  61. package/internal-entity-heuristics.mjs +28 -8
  62. package/internal-mapping-form.d.cts +1 -1
  63. package/internal-mapping-form.d.mts +1 -1
  64. package/internal-mappings-config.cjs +1 -1
  65. package/internal-mappings-config.d.cts +1 -1
  66. package/internal-mappings-config.d.mts +1 -1
  67. package/internal-mappings-config.mjs +1 -1
  68. package/internal-sync-engine.cjs +1 -1
  69. package/internal-sync-engine.d.cts +1 -1
  70. package/internal-sync-engine.d.mts +1 -1
  71. package/internal-sync-engine.mjs +1 -1
  72. package/internal-view-compiler.cjs +1 -1
  73. package/internal-view-compiler.d.cts +1 -1
  74. package/internal-view-compiler.d.mts +1 -1
  75. package/internal-view-compiler.mjs +1 -1
  76. package/internal.cjs +21 -4
  77. package/internal.d.cts +7 -6
  78. package/internal.d.mts +7 -6
  79. package/internal.mjs +7 -5
  80. package/{mapping-form-D93lhHEc.d.mts → mapping-form-43bwOTat.d.cts} +1 -1
  81. package/{mapping-form-lfyEE7EJ.d.cts → mapping-form-DUvWUYCo.d.mts} +1 -1
  82. package/{mappings-config-BsRADNRv.cjs → mappings-config-BSSwdHiq.cjs} +32 -6
  83. package/mappings-config-BpcR8bBo.d.mts +167 -0
  84. package/{mappings-config-Dbgxx3Nv.mjs → mappings-config-bJQT_gSa.mjs} +32 -6
  85. package/mappings-config-xsLMn3I-.d.cts +167 -0
  86. package/namespace-probe-BSH_p9TK.d.cts +381 -0
  87. package/namespace-probe-Dsp5uNkS.d.mts +381 -0
  88. package/package.json +1 -1
  89. package/{entity-config-va2bkH5o.mjs → projection-C5244vGa.cjs} +130 -309
  90. package/{entity-config-D87rV-tE.cjs → projection-D7xmQP4S.mjs} +60 -381
  91. package/{sdk-iqOXeWIp.cjs → sdk-Bj-ZDf4u.cjs} +126 -28
  92. package/{sdk-C6WANW8M.mjs → sdk-BvRD2jAp.mjs} +126 -28
  93. package/sdk.cjs +2 -2
  94. package/sdk.d.cts +36 -1
  95. package/sdk.d.mts +36 -1
  96. package/sdk.mjs +2 -2
  97. package/{sync-engine-Do5ru3WF.mjs → sync-engine-Bg6-SznL.mjs} +9 -2
  98. package/{sync-engine-CzEbpQGv.cjs → sync-engine-DEJvKw6E.cjs} +9 -2
  99. package/{sync-engine-DGk_AeHJ.d.mts → sync-engine-GNqRB8eS.d.cts} +2 -2
  100. package/{sync-engine-B7QIbXro.d.cts → sync-engine-ZsusW-q_.d.mts} +2 -2
  101. package/{view-compiler-BWz0sGdm.d.cts → view-compiler-Cin0neDO.d.mts} +1 -1
  102. package/{view-compiler-ChWr_Lml.mjs → view-compiler-DlTpOfZi.mjs} +81 -12
  103. package/{view-compiler-BIwvm-o2.cjs → view-compiler-DplczSjF.cjs} +81 -12
  104. package/{view-compiler-Bn_EJJMO.d.mts → view-compiler-Ll9cbIJz.d.cts} +1 -1
  105. package/vite.d.cts +1 -1
  106. package/vite.d.mts +1 -1
  107. package/drizzle-B89tLo4T.mjs +0 -31
  108. package/drizzle-CFOr9dU9.d.mts +0 -20
  109. package/drizzle-DiReZf6d.cjs +0 -36
  110. package/drizzle-DmeKSqeF.d.cts +0 -20
  111. package/mappings-config-DsUa7-1w.d.mts +0 -41
  112. package/mappings-config-XmzB4dag.d.cts +0 -41
  113. package/types-CsL0rFYh.d.cts +0 -155
  114. package/types-CsL0rFYh.d.mts +0 -155
package/vite.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as ClivlySDK } from "./types-CsL0rFYh.mjs";
1
+ import { o as ClivlySDK } from "./namespace-probe-Dsp5uNkS.mjs";
2
2
  import { Plugin } from "vite";
3
3
  //#region ../sdk/src/vite.d.ts
4
4
  interface ClivlyViteOptions {
@@ -1,31 +0,0 @@
1
- import { Table, getTableColumns, getTableName, is } from "drizzle-orm";
2
- //#region ../core/src/drizzle.ts
3
- /**
4
- * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
5
- * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
6
- * delivers the "reads your schema" promise for Drizzle hosts: no hand-authored
7
- * `DiscoveredTable[]`. Feed the result to the SDK's `schema` option, or diff it
8
- * against your entity config.
9
- *
10
- * Column names are the real database column names (e.g. `full_name`), not the
11
- * Drizzle property keys (`fullName`). Non-table values in the schema object
12
- * (relations, enums, helpers) are ignored.
13
- *
14
- * `drizzle-orm` is an **optional peer dependency** — you only need it installed
15
- * when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
16
- * stays dependency-free.
17
- */
18
- function discoverFromDrizzle(schema) {
19
- const tables = [];
20
- for (const value of Object.values(schema)) {
21
- if (!is(value, Table)) continue;
22
- const columns = getTableColumns(value);
23
- tables.push({
24
- name: getTableName(value),
25
- columns: Object.values(columns).map((column) => column.name)
26
- });
27
- }
28
- return tables;
29
- }
30
- //#endregion
31
- export { discoverFromDrizzle as t };
@@ -1,20 +0,0 @@
1
- import { u as DiscoveredSchemaTable } from "./entity-config-DoUCXtq5.mjs";
2
- //#region ../core/src/drizzle.d.ts
3
- /**
4
- * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
5
- * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
6
- * delivers the "reads your schema" promise for Drizzle hosts: no hand-authored
7
- * `DiscoveredTable[]`. Feed the result to the SDK's `schema` option, or diff it
8
- * against your entity config.
9
- *
10
- * Column names are the real database column names (e.g. `full_name`), not the
11
- * Drizzle property keys (`fullName`). Non-table values in the schema object
12
- * (relations, enums, helpers) are ignored.
13
- *
14
- * `drizzle-orm` is an **optional peer dependency** — you only need it installed
15
- * when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
16
- * stays dependency-free.
17
- */
18
- declare function discoverFromDrizzle(schema: Record<string, unknown>): DiscoveredSchemaTable[];
19
- //#endregion
20
- export { discoverFromDrizzle as t };
@@ -1,36 +0,0 @@
1
- let drizzle_orm = require("drizzle-orm");
2
- //#region ../core/src/drizzle.ts
3
- /**
4
- * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
5
- * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
6
- * delivers the "reads your schema" promise for Drizzle hosts: no hand-authored
7
- * `DiscoveredTable[]`. Feed the result to the SDK's `schema` option, or diff it
8
- * against your entity config.
9
- *
10
- * Column names are the real database column names (e.g. `full_name`), not the
11
- * Drizzle property keys (`fullName`). Non-table values in the schema object
12
- * (relations, enums, helpers) are ignored.
13
- *
14
- * `drizzle-orm` is an **optional peer dependency** — you only need it installed
15
- * when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
16
- * stays dependency-free.
17
- */
18
- function discoverFromDrizzle(schema) {
19
- const tables = [];
20
- for (const value of Object.values(schema)) {
21
- if (!(0, drizzle_orm.is)(value, drizzle_orm.Table)) continue;
22
- const columns = (0, drizzle_orm.getTableColumns)(value);
23
- tables.push({
24
- name: (0, drizzle_orm.getTableName)(value),
25
- columns: Object.values(columns).map((column) => column.name)
26
- });
27
- }
28
- return tables;
29
- }
30
- //#endregion
31
- Object.defineProperty(exports, "discoverFromDrizzle", {
32
- enumerable: true,
33
- get: function() {
34
- return discoverFromDrizzle;
35
- }
36
- });
@@ -1,20 +0,0 @@
1
- import { u as DiscoveredSchemaTable } from "./entity-config-DoUCXtq5.cjs";
2
- //#region ../core/src/drizzle.d.ts
3
- /**
4
- * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
5
- * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
6
- * delivers the "reads your schema" promise for Drizzle hosts: no hand-authored
7
- * `DiscoveredTable[]`. Feed the result to the SDK's `schema` option, or diff it
8
- * against your entity config.
9
- *
10
- * Column names are the real database column names (e.g. `full_name`), not the
11
- * Drizzle property keys (`fullName`). Non-table values in the schema object
12
- * (relations, enums, helpers) are ignored.
13
- *
14
- * `drizzle-orm` is an **optional peer dependency** — you only need it installed
15
- * when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
16
- * stays dependency-free.
17
- */
18
- declare function discoverFromDrizzle(schema: Record<string, unknown>): DiscoveredSchemaTable[];
19
- //#endregion
20
- export { discoverFromDrizzle as t };
@@ -1,41 +0,0 @@
1
- import { a as ClivlyEntitiesConfig } from "./entity-config-DoUCXtq5.mjs";
2
- //#region ../core/src/mappings-config.d.ts
3
- /**
4
- * Mappings → Entity Config bridge.
5
- *
6
- * `crm_entity_mappings` rows are the single source of truth for how a host
7
- * schema maps onto Clivly's CRM concepts. This module compiles those rows into
8
- * a `ClivlyEntitiesConfig` — the contract the view compiler and sync engine
9
- * consume — so the persisted mapping and the runtime pipeline never diverge.
10
- *
11
- * The row model has no explicit entity-key column (it's keyed by
12
- * `sourceTable + targetConcept + role`), but the config's `relationships`
13
- * reference other entities *by key*. This builder therefore derives a stable
14
- * key per row and resolves each relationship's `entity` reference through the
15
- * same derivation — so a relationship stored as `entity: "<relatedTable>"`
16
- * (the shape `mappings.suggest` produces) resolves to the right entity.
17
- */
18
- /**
19
- * A persisted `crm_entity_mappings` row, narrowed to the columns the builder
20
- * reads. Structurally compatible with the Drizzle row (jsonb columns typed
21
- * loosely) so the API layer can pass `db.select()` results straight in.
22
- */
23
- interface EntityMappingRow {
24
- fieldMap: Record<string, string>;
25
- filter?: Record<string, unknown> | null;
26
- relationships?: Record<string, unknown> | null;
27
- role?: string | null;
28
- sourceTable: string;
29
- status?: string | null;
30
- targetConcept: string;
31
- targetObjectTypeId?: string | null;
32
- }
33
- /**
34
- * Compile persisted mapping rows into a `ClivlyEntitiesConfig`. Only `active`
35
- * rows with at least one mapped field are included; disabled/suggested rows and
36
- * unmapped rows are skipped. Returns `{ entities: {} }` when nothing is
37
- * eligible — a no-op the view compiler and sync engine both tolerate.
38
- */
39
- declare function mappingsToEntitiesConfig(rows: EntityMappingRow[]): ClivlyEntitiesConfig;
40
- //#endregion
41
- export { mappingsToEntitiesConfig as n, EntityMappingRow as t };
@@ -1,41 +0,0 @@
1
- import { a as ClivlyEntitiesConfig } from "./entity-config-DoUCXtq5.cjs";
2
- //#region ../core/src/mappings-config.d.ts
3
- /**
4
- * Mappings → Entity Config bridge.
5
- *
6
- * `crm_entity_mappings` rows are the single source of truth for how a host
7
- * schema maps onto Clivly's CRM concepts. This module compiles those rows into
8
- * a `ClivlyEntitiesConfig` — the contract the view compiler and sync engine
9
- * consume — so the persisted mapping and the runtime pipeline never diverge.
10
- *
11
- * The row model has no explicit entity-key column (it's keyed by
12
- * `sourceTable + targetConcept + role`), but the config's `relationships`
13
- * reference other entities *by key*. This builder therefore derives a stable
14
- * key per row and resolves each relationship's `entity` reference through the
15
- * same derivation — so a relationship stored as `entity: "<relatedTable>"`
16
- * (the shape `mappings.suggest` produces) resolves to the right entity.
17
- */
18
- /**
19
- * A persisted `crm_entity_mappings` row, narrowed to the columns the builder
20
- * reads. Structurally compatible with the Drizzle row (jsonb columns typed
21
- * loosely) so the API layer can pass `db.select()` results straight in.
22
- */
23
- interface EntityMappingRow {
24
- fieldMap: Record<string, string>;
25
- filter?: Record<string, unknown> | null;
26
- relationships?: Record<string, unknown> | null;
27
- role?: string | null;
28
- sourceTable: string;
29
- status?: string | null;
30
- targetConcept: string;
31
- targetObjectTypeId?: string | null;
32
- }
33
- /**
34
- * Compile persisted mapping rows into a `ClivlyEntitiesConfig`. Only `active`
35
- * rows with at least one mapped field are included; disabled/suggested rows and
36
- * unmapped rows are skipped. Returns `{ entities: {} }` when nothing is
37
- * eligible — a no-op the view compiler and sync engine both tolerate.
38
- */
39
- declare function mappingsToEntitiesConfig(rows: EntityMappingRow[]): ClivlyEntitiesConfig;
40
- //#endregion
41
- export { mappingsToEntitiesConfig as n, EntityMappingRow as t };
@@ -1,155 +0,0 @@
1
- //#region ../sdk/src/drizzle-meta.d.ts
2
- declare const DRIZZLE_META: "__clivly_drizzle_source_meta__";
3
- interface DrizzleSourceMeta {
4
- /** Drizzle property keys of every column on the source table. */
5
- columnKeys: string[];
6
- /** Schema-v2 typed column metadata derived from the Drizzle table. */
7
- columnsMeta?: DiscoveredColumn[];
8
- cursorField: string;
9
- idField: string;
10
- /** The backing table's real name, so discovery can key metadata by table. */
11
- tableName?: string;
12
- }
13
- //#endregion
14
- //#region ../sdk/src/types.d.ts
15
- interface DiscoveredColumn {
16
- isForeignKey?: boolean;
17
- isPrimaryKey?: boolean;
18
- name: string;
19
- nullable?: boolean;
20
- /** The column this FK points at, when it is a foreign key. */
21
- references?: {
22
- table: string;
23
- column: string;
24
- };
25
- /** SQL/driver type, e.g. "text", "integer", "timestamp". */
26
- type?: string;
27
- }
28
- interface ClivlyUser {
29
- email: string;
30
- id: string;
31
- name?: string;
32
- }
33
- interface DoctorCheck {
34
- /** Human-readable outcome — what passed, or why it failed. */
35
- detail: string;
36
- /** Short label, e.g. "API key present". */
37
- name: string;
38
- /** True when the check passed. Ignored when `skipped` is true. */
39
- ok: boolean;
40
- /** True when the check could not run (e.g. a hand-written source). */
41
- skipped?: boolean;
42
- }
43
- interface DoctorReport {
44
- checks: DoctorCheck[];
45
- /** AND of every non-skipped check's `ok`. */
46
- ok: boolean;
47
- }
48
- type ClivlyConnectReason = "ok" | "invalid_api_key" | "forbidden" | "rate_limited" | "server_error" | "client_error" | "network_error";
49
- interface ClivlyConnectResult {
50
- ok: boolean;
51
- /** Org resolved from a successful heartbeat, when the server returns it. */
52
- org?: {
53
- id?: string;
54
- name?: string;
55
- };
56
- reason: ClivlyConnectReason;
57
- /** Whether a retry could plausibly succeed (network, 429, 5xx). */
58
- retryable: boolean;
59
- /** HTTP status, or null when the request never completed (network error). */
60
- status: number | null;
61
- }
62
- interface SyncCursor {
63
- /** The row's id, breaking ties when timestamps collide. */
64
- id: string;
65
- /** The row's cursor-field value (typically `updated_at`). */
66
- time: Date;
67
- }
68
- interface SyncSource {
69
- cursorField: string;
70
- entity: string;
71
- fetchPage(args: {
72
- since: SyncCursor | null;
73
- limit: number;
74
- }): Promise<Record<string, unknown>[]>;
75
- /** Stable, unique tie-breaker column for keyset paging. Defaults to "id". */
76
- idField?: string;
77
- /** Set by `fromDrizzle`; lets `doctor` introspect the backing table. */
78
- [DRIZZLE_META]?: DrizzleSourceMeta;
79
- }
80
- type SyncMode = "delta" | "full";
81
- interface ClivlySDK {
82
- /**
83
- * Send a single heartbeat and report the outcome richly: `ok`, the HTTP
84
- * `status` (null on network failure), a coarse `reason`, whether it's
85
- * `retryable`, and the resolved `org` when the server returns it. Never throws
86
- * — inspect the result, or turn a failure into an exception with
87
- * `ClivlyError.from(result)`. Prefer this over `heartbeat()` for onboarding,
88
- * health checks, and one-shot serverless calls.
89
- */
90
- connect(): Promise<ClivlyConnectResult>;
91
- /**
92
- * Build the `/clivly/auth/verify` handler the developer mounts in their app.
93
- * Clivly's cloud calls it to validate a CRM user's identity against the host
94
- * app's session. Pass a resolver that reads the host session from the request.
95
- *
96
- * The handler authenticates the caller against `config.verifyToken` (presented
97
- * as `Authorization: Bearer <token>`) before invoking the resolver, so the
98
- * endpoint can't be used by third parties to probe host sessions. It fails
99
- * closed with HTTP 503 if `verifyToken` is unset (a missing config value, not a
100
- * server fault — so it won't trip the host's 5xx error alerting).
101
- */
102
- createAuthVerifyHandler(resolveUser: (req: Request) => Promise<ClivlyUser | null> | ClivlyUser | null): (req: Request) => Promise<Response>;
103
- /**
104
- * A fetch handler to mount at a route. Each request runs one `runScheduled()`
105
- * and returns JSON: 200 when the sync succeeded, 500 otherwise.
106
- *
107
- * Two callers use it: Clivly Cloud (when someone clicks "Run sync" — those
108
- * requests are HMAC-signed and carry a run id), and the host's own scheduler
109
- * (Workers cron, an uptime ping — no body).
110
- *
111
- * When `syncTrigger.secret` is set the handler rejects unsigned or
112
- * badly-signed requests with 401. When it isn't, the route stays open to
113
- * anyone who can reach it — set a secret if it's publicly routable.
114
- */
115
- createClivlyHandler(): (req: Request) => Promise<Response>;
116
- /** Validate this setup end-to-end (read-only) before the first sync. */
117
- doctor(): Promise<DoctorReport>;
118
- /**
119
- * Send a single heartbeat now. Returns true on success. Kept for the keep-alive
120
- * loop and back-compat; use `connect()` when you need the failure reason.
121
- */
122
- heartbeat(): Promise<boolean>;
123
- /**
124
- * One-shot heartbeat + a single sync, with no keep-alive timers. The correct
125
- * entry point on serverless/edge (Workers, Vercel, Lambda), where `start()`'s
126
- * `setInterval` loop can't persist between invocations — call this from a
127
- * scheduled/cron trigger. Throws if a sync push fails (so the run is marked
128
- * failed); heartbeat is best-effort.
129
- */
130
- runScheduled(options?: {
131
- mode?: SyncMode;
132
- runId?: string;
133
- }): Promise<void>;
134
- /**
135
- * Send the initial heartbeat and start the keep-alive loop. For long-lived
136
- * hosts only — on serverless/edge the interval can't persist, so prefer
137
- * `runScheduled()` / `createClivlyHandler()`. Emits a warning if a serverless
138
- * runtime is detected.
139
- */
140
- start(): Promise<void>;
141
- /** Stop the keep-alive loop. */
142
- stop(): void;
143
- /**
144
- * Sync all configured sources now. `delta` (default) pages changed rows since
145
- * the last cursor; `full` pushes each complete entity so the server can
146
- * reconcile leavers (archive-on-leave). Throws if a push fails, so callers see
147
- * the failure — the background keep-alive loop swallows and retries instead.
148
- */
149
- sync(options?: {
150
- mode?: SyncMode;
151
- runId?: string;
152
- }): Promise<void>;
153
- }
154
- //#endregion
155
- export { SyncSource as n, ClivlySDK as t };
@@ -1,155 +0,0 @@
1
- //#region ../sdk/src/drizzle-meta.d.ts
2
- declare const DRIZZLE_META: "__clivly_drizzle_source_meta__";
3
- interface DrizzleSourceMeta {
4
- /** Drizzle property keys of every column on the source table. */
5
- columnKeys: string[];
6
- /** Schema-v2 typed column metadata derived from the Drizzle table. */
7
- columnsMeta?: DiscoveredColumn[];
8
- cursorField: string;
9
- idField: string;
10
- /** The backing table's real name, so discovery can key metadata by table. */
11
- tableName?: string;
12
- }
13
- //#endregion
14
- //#region ../sdk/src/types.d.ts
15
- interface DiscoveredColumn {
16
- isForeignKey?: boolean;
17
- isPrimaryKey?: boolean;
18
- name: string;
19
- nullable?: boolean;
20
- /** The column this FK points at, when it is a foreign key. */
21
- references?: {
22
- table: string;
23
- column: string;
24
- };
25
- /** SQL/driver type, e.g. "text", "integer", "timestamp". */
26
- type?: string;
27
- }
28
- interface ClivlyUser {
29
- email: string;
30
- id: string;
31
- name?: string;
32
- }
33
- interface DoctorCheck {
34
- /** Human-readable outcome — what passed, or why it failed. */
35
- detail: string;
36
- /** Short label, e.g. "API key present". */
37
- name: string;
38
- /** True when the check passed. Ignored when `skipped` is true. */
39
- ok: boolean;
40
- /** True when the check could not run (e.g. a hand-written source). */
41
- skipped?: boolean;
42
- }
43
- interface DoctorReport {
44
- checks: DoctorCheck[];
45
- /** AND of every non-skipped check's `ok`. */
46
- ok: boolean;
47
- }
48
- type ClivlyConnectReason = "ok" | "invalid_api_key" | "forbidden" | "rate_limited" | "server_error" | "client_error" | "network_error";
49
- interface ClivlyConnectResult {
50
- ok: boolean;
51
- /** Org resolved from a successful heartbeat, when the server returns it. */
52
- org?: {
53
- id?: string;
54
- name?: string;
55
- };
56
- reason: ClivlyConnectReason;
57
- /** Whether a retry could plausibly succeed (network, 429, 5xx). */
58
- retryable: boolean;
59
- /** HTTP status, or null when the request never completed (network error). */
60
- status: number | null;
61
- }
62
- interface SyncCursor {
63
- /** The row's id, breaking ties when timestamps collide. */
64
- id: string;
65
- /** The row's cursor-field value (typically `updated_at`). */
66
- time: Date;
67
- }
68
- interface SyncSource {
69
- cursorField: string;
70
- entity: string;
71
- fetchPage(args: {
72
- since: SyncCursor | null;
73
- limit: number;
74
- }): Promise<Record<string, unknown>[]>;
75
- /** Stable, unique tie-breaker column for keyset paging. Defaults to "id". */
76
- idField?: string;
77
- /** Set by `fromDrizzle`; lets `doctor` introspect the backing table. */
78
- [DRIZZLE_META]?: DrizzleSourceMeta;
79
- }
80
- type SyncMode = "delta" | "full";
81
- interface ClivlySDK {
82
- /**
83
- * Send a single heartbeat and report the outcome richly: `ok`, the HTTP
84
- * `status` (null on network failure), a coarse `reason`, whether it's
85
- * `retryable`, and the resolved `org` when the server returns it. Never throws
86
- * — inspect the result, or turn a failure into an exception with
87
- * `ClivlyError.from(result)`. Prefer this over `heartbeat()` for onboarding,
88
- * health checks, and one-shot serverless calls.
89
- */
90
- connect(): Promise<ClivlyConnectResult>;
91
- /**
92
- * Build the `/clivly/auth/verify` handler the developer mounts in their app.
93
- * Clivly's cloud calls it to validate a CRM user's identity against the host
94
- * app's session. Pass a resolver that reads the host session from the request.
95
- *
96
- * The handler authenticates the caller against `config.verifyToken` (presented
97
- * as `Authorization: Bearer <token>`) before invoking the resolver, so the
98
- * endpoint can't be used by third parties to probe host sessions. It fails
99
- * closed with HTTP 503 if `verifyToken` is unset (a missing config value, not a
100
- * server fault — so it won't trip the host's 5xx error alerting).
101
- */
102
- createAuthVerifyHandler(resolveUser: (req: Request) => Promise<ClivlyUser | null> | ClivlyUser | null): (req: Request) => Promise<Response>;
103
- /**
104
- * A fetch handler to mount at a route. Each request runs one `runScheduled()`
105
- * and returns JSON: 200 when the sync succeeded, 500 otherwise.
106
- *
107
- * Two callers use it: Clivly Cloud (when someone clicks "Run sync" — those
108
- * requests are HMAC-signed and carry a run id), and the host's own scheduler
109
- * (Workers cron, an uptime ping — no body).
110
- *
111
- * When `syncTrigger.secret` is set the handler rejects unsigned or
112
- * badly-signed requests with 401. When it isn't, the route stays open to
113
- * anyone who can reach it — set a secret if it's publicly routable.
114
- */
115
- createClivlyHandler(): (req: Request) => Promise<Response>;
116
- /** Validate this setup end-to-end (read-only) before the first sync. */
117
- doctor(): Promise<DoctorReport>;
118
- /**
119
- * Send a single heartbeat now. Returns true on success. Kept for the keep-alive
120
- * loop and back-compat; use `connect()` when you need the failure reason.
121
- */
122
- heartbeat(): Promise<boolean>;
123
- /**
124
- * One-shot heartbeat + a single sync, with no keep-alive timers. The correct
125
- * entry point on serverless/edge (Workers, Vercel, Lambda), where `start()`'s
126
- * `setInterval` loop can't persist between invocations — call this from a
127
- * scheduled/cron trigger. Throws if a sync push fails (so the run is marked
128
- * failed); heartbeat is best-effort.
129
- */
130
- runScheduled(options?: {
131
- mode?: SyncMode;
132
- runId?: string;
133
- }): Promise<void>;
134
- /**
135
- * Send the initial heartbeat and start the keep-alive loop. For long-lived
136
- * hosts only — on serverless/edge the interval can't persist, so prefer
137
- * `runScheduled()` / `createClivlyHandler()`. Emits a warning if a serverless
138
- * runtime is detected.
139
- */
140
- start(): Promise<void>;
141
- /** Stop the keep-alive loop. */
142
- stop(): void;
143
- /**
144
- * Sync all configured sources now. `delta` (default) pages changed rows since
145
- * the last cursor; `full` pushes each complete entity so the server can
146
- * reconcile leavers (archive-on-leave). Throws if a push fails, so callers see
147
- * the failure — the background keep-alive loop swallows and retries instead.
148
- */
149
- sync(options?: {
150
- mode?: SyncMode;
151
- runId?: string;
152
- }): Promise<void>;
153
- }
154
- //#endregion
155
- export { SyncSource as n, ClivlySDK as t };