clivly 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +330 -134
- package/core-drizzle.cjs +3 -1
- package/core-drizzle.d.cts +3 -2
- package/core-drizzle.d.mts +3 -2
- package/core-drizzle.mjs +2 -2
- package/core-entity-config.cjs +2 -1
- package/core-entity-config.d.cts +2 -2
- package/core-entity-config.d.mts +2 -2
- package/core-entity-config.mjs +2 -2
- package/core-entity-heuristics.d.cts +3 -2
- package/core-entity-heuristics.d.mts +3 -2
- package/core-mapping-form.d.cts +1 -1
- package/core-mapping-form.d.mts +1 -1
- package/core-mappings-config.cjs +1 -1
- package/core-mappings-config.d.cts +1 -1
- package/core-mappings-config.d.mts +1 -1
- package/core-mappings-config.mjs +1 -1
- package/core-sync-engine.cjs +1 -1
- package/core-sync-engine.d.cts +1 -1
- package/core-sync-engine.d.mts +1 -1
- package/core-sync-engine.mjs +1 -1
- package/core-view-compiler.cjs +2 -1
- package/core-view-compiler.d.cts +2 -2
- package/core-view-compiler.d.mts +2 -2
- package/core-view-compiler.mjs +2 -2
- package/core.cjs +21 -5
- package/core.d.cts +7 -6
- package/core.d.mts +7 -6
- package/core.mjs +7 -6
- package/drizzle-3kvhkwO7.mjs +110 -0
- package/drizzle-DooDUGqO.d.mts +41 -0
- package/drizzle-bfjVzYR6.cjs +127 -0
- package/drizzle-jz0lrAgl.d.cts +41 -0
- package/drizzle.cjs +12 -40
- package/drizzle.d.cts +3 -11
- package/drizzle.d.mts +3 -11
- package/drizzle.mjs +12 -41
- package/entity-config-D08zAeFY.mjs +657 -0
- package/{entity-config-DoUCXtq5.d.cts → entity-config-fKQhimtD.d.cts} +263 -2
- package/{entity-config-DoUCXtq5.d.mts → entity-config-fKQhimtD.d.mts} +263 -2
- package/entity-config-nuXge6rY.cjs +778 -0
- package/index.cjs +768 -122
- package/index.d.cts +12 -0
- package/index.d.mts +12 -0
- package/index.mjs +769 -123
- package/internal-BGVUG312.mjs +68 -0
- package/internal-BLCK81kB.d.mts +72 -0
- package/internal-C-YBW2DB.d.cts +72 -0
- package/internal-D4HDi2GC.cjs +97 -0
- package/internal-drizzle.cjs +3 -1
- package/internal-drizzle.d.cts +2 -2
- package/internal-drizzle.d.mts +2 -2
- package/internal-drizzle.mjs +2 -2
- package/internal-entity-config.cjs +2 -1
- package/internal-entity-config.d.cts +2 -2
- package/internal-entity-config.d.mts +2 -2
- package/internal-entity-config.mjs +2 -2
- package/internal-entity-heuristics.cjs +28 -8
- package/internal-entity-heuristics.d.cts +2 -12
- package/internal-entity-heuristics.d.mts +2 -12
- package/internal-entity-heuristics.mjs +28 -8
- package/internal-mapping-form.d.cts +1 -1
- package/internal-mapping-form.d.mts +1 -1
- package/internal-mappings-config.cjs +1 -1
- package/internal-mappings-config.d.cts +1 -1
- package/internal-mappings-config.d.mts +1 -1
- package/internal-mappings-config.mjs +1 -1
- package/internal-sync-engine.cjs +1 -1
- package/internal-sync-engine.d.cts +1 -1
- package/internal-sync-engine.d.mts +1 -1
- package/internal-sync-engine.mjs +1 -1
- package/internal-view-compiler.cjs +2 -1
- package/internal-view-compiler.d.cts +2 -2
- package/internal-view-compiler.d.mts +2 -2
- package/internal-view-compiler.mjs +2 -2
- package/internal.cjs +21 -4
- package/internal.d.cts +7 -6
- package/internal.d.mts +7 -6
- package/internal.mjs +7 -5
- package/{mapping-form-D93lhHEc.d.mts → mapping-form-DhY0iFmN.d.cts} +1 -1
- package/{mapping-form-lfyEE7EJ.d.cts → mapping-form-Du36VZr1.d.mts} +1 -1
- package/{mappings-config-DsUa7-1w.d.mts → mappings-config-B1qNM8VL.d.cts} +7 -1
- package/{mappings-config-XmzB4dag.d.cts → mappings-config-BChZsany.d.mts} +7 -1
- package/{mappings-config-BsRADNRv.cjs → mappings-config-C8ynKmDK.cjs} +32 -6
- package/{mappings-config-Dbgxx3Nv.mjs → mappings-config-DNaYGyKN.mjs} +32 -6
- package/namespace-probe-BkUs8raG.d.mts +381 -0
- package/namespace-probe-aRFmpU85.d.cts +381 -0
- package/package.json +1 -1
- package/{entity-config-va2bkH5o.mjs → projection-C5244vGa.cjs} +130 -309
- package/{entity-config-D87rV-tE.cjs → projection-D7xmQP4S.mjs} +60 -381
- package/{sdk-iqOXeWIp.cjs → sdk-Bj-ZDf4u.cjs} +126 -28
- package/{sdk-C6WANW8M.mjs → sdk-BvRD2jAp.mjs} +126 -28
- package/sdk.cjs +2 -2
- package/sdk.d.cts +36 -1
- package/sdk.d.mts +36 -1
- package/sdk.mjs +2 -2
- package/{sync-engine-DGk_AeHJ.d.mts → sync-engine-DHQ7rXZe.d.mts} +2 -2
- package/{sync-engine-B7QIbXro.d.cts → sync-engine-DiPjH53O.d.cts} +2 -2
- package/{sync-engine-Do5ru3WF.mjs → sync-engine-SuxSzbZ4.mjs} +9 -2
- package/{sync-engine-CzEbpQGv.cjs → sync-engine-abE94g6X.cjs} +9 -2
- package/{view-compiler-BIwvm-o2.cjs → view-compiler-Blu4OXJ7.cjs} +103 -12
- package/{view-compiler-ChWr_Lml.mjs → view-compiler-CQx8TRrW.mjs} +98 -13
- package/{view-compiler-BWz0sGdm.d.cts → view-compiler-CcUwzZut.d.mts} +12 -2
- package/{view-compiler-Bn_EJJMO.d.mts → view-compiler-DqAdVxLq.d.cts} +12 -2
- package/vite.d.cts +1 -1
- package/vite.d.mts +1 -1
- package/drizzle-B89tLo4T.mjs +0 -31
- package/drizzle-CFOr9dU9.d.mts +0 -20
- package/drizzle-DiReZf6d.cjs +0 -36
- package/drizzle-DmeKSqeF.d.cts +0 -20
- package/types-CsL0rFYh.d.cts +0 -155
- package/types-CsL0rFYh.d.mts +0 -155
|
@@ -1,3 +1,58 @@
|
|
|
1
|
+
import { r as identityRefs, t as BASE_REF } from "./projection-D7xmQP4S.mjs";
|
|
2
|
+
//#region ../core/src/projection-sql.ts
|
|
3
|
+
/**
|
|
4
|
+
* SQL generation for projection-backed entities.
|
|
5
|
+
*
|
|
6
|
+
* Base and joins are aliased by their ref key (`base`, then each join's `key`),
|
|
7
|
+
* which is what allows the same table to be joined twice and keeps generated
|
|
8
|
+
* SQL independent of host table names.
|
|
9
|
+
*
|
|
10
|
+
* Pure string generation — no DB access. Identifiers are escaped so output is
|
|
11
|
+
* deterministic and injection-safe.
|
|
12
|
+
*/
|
|
13
|
+
/** Quote a single identifier part, escaping embedded double-quotes. */
|
|
14
|
+
function quoteIdent(name) {
|
|
15
|
+
return `"${name.replace(/"/g, "\"\"")}"`;
|
|
16
|
+
}
|
|
17
|
+
function refSql(ref) {
|
|
18
|
+
return `${quoteIdent(ref.table)}.${quoteIdent(ref.column)}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The identity expression, aliased as `id`. Composite identities concatenate
|
|
22
|
+
* their parts with `::`; validation guarantees every part is NOT NULL and
|
|
23
|
+
* non-text, which is what makes the concatenation collision-free.
|
|
24
|
+
*/
|
|
25
|
+
function identitySql(projection, basePkColumn) {
|
|
26
|
+
const refs = identityRefs(projection.identity, basePkColumn);
|
|
27
|
+
if (projection.identity.kind === "composite") return `CONCAT_WS('::', ${refs.map((ref) => `${refSql(ref)}::text`).join(", ")}) AS ${quoteIdent("id")}`;
|
|
28
|
+
const [ref] = refs;
|
|
29
|
+
if (!ref) throw new Error("projection identity resolved to no column");
|
|
30
|
+
return `${refSql(ref)} AS ${quoteIdent("id")}`;
|
|
31
|
+
}
|
|
32
|
+
function compileProjectionSelect(projection, basePkColumn) {
|
|
33
|
+
const selectItems = [identitySql(projection, basePkColumn)];
|
|
34
|
+
const columns = ["id"];
|
|
35
|
+
for (const [field, binding] of Object.entries(projection.fieldBindings)) {
|
|
36
|
+
selectItems.push(`${refSql(binding.from)} AS ${quoteIdent(field)}`);
|
|
37
|
+
columns.push(field);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
columns,
|
|
41
|
+
selectItems
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function compileProjectionJoins(projection) {
|
|
45
|
+
return projection.joins.map((join) => {
|
|
46
|
+
const keyword = join.type === "inner" ? "INNER JOIN" : "LEFT JOIN";
|
|
47
|
+
const on = join.on.map((c) => `${refSql(c.left)} = ${refSql(c.right)}`).join(" AND ");
|
|
48
|
+
return `${keyword} ${quoteIdent(join.table)} AS ${quoteIdent(join.key)} ON ${on}`;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** `FROM <baseTable> AS "base"` — the alias every ref resolves against. */
|
|
52
|
+
function compileProjectionFrom(projection) {
|
|
53
|
+
return `FROM ${quoteIdent(projection.baseTable)} AS ${quoteIdent(BASE_REF)}`;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
1
56
|
//#region ../core/src/view-compiler.ts
|
|
2
57
|
/**
|
|
3
58
|
* View compiler (Phase 2) — turns a validated entity config into read-only
|
|
@@ -22,10 +77,6 @@
|
|
|
22
77
|
const SOURCE_KEY = "id";
|
|
23
78
|
const DEFAULT_VIEW_PREFIX = "crm_src_";
|
|
24
79
|
const DEFAULT_ROLE = "primary";
|
|
25
|
-
/** Quote a single identifier part, escaping embedded double-quotes. */
|
|
26
|
-
function quoteIdent(name) {
|
|
27
|
-
return `"${name.replace(/"/g, "\"\"")}"`;
|
|
28
|
-
}
|
|
29
80
|
/** Emit a SQL literal for a scalar filter value. */
|
|
30
81
|
function quoteLiteral(value) {
|
|
31
82
|
if (typeof value === "number") return String(value);
|
|
@@ -106,17 +157,24 @@ function compileRelationship(relName, rel, source, related) {
|
|
|
106
157
|
refColumn: refCol
|
|
107
158
|
};
|
|
108
159
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (!entity) throw new Error(`entity "${entityKey}" is not defined`);
|
|
112
|
-
const viewName = `${options.viewPrefix ?? "crm_src_"}${entityKey}`;
|
|
113
|
-
const src = entity.source;
|
|
160
|
+
/** SELECT items for a legacy single-table entity: source key, then fields. */
|
|
161
|
+
function legacySelect(entity, src) {
|
|
114
162
|
const selectItems = [`${quoteIdent(src)}.${quoteIdent(SOURCE_KEY)} AS ${quoteIdent("id")}`];
|
|
115
163
|
const columns = ["id"];
|
|
116
164
|
for (const [field, column] of Object.entries(entity.fields)) {
|
|
117
165
|
selectItems.push(`${quoteIdent(src)}.${quoteIdent(column)} AS ${quoteIdent(field)}`);
|
|
118
166
|
columns.push(field);
|
|
119
167
|
}
|
|
168
|
+
return {
|
|
169
|
+
columns,
|
|
170
|
+
selectItems
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Relationship JOINs for a legacy entity. Appends each relationship's ref
|
|
175
|
+
* column to `columns`/`selectItems` in place, preserving the existing order.
|
|
176
|
+
*/
|
|
177
|
+
function legacyJoins(config, entity, columns, selectItems) {
|
|
120
178
|
const joins = [];
|
|
121
179
|
for (const [relName, rel] of Object.entries(entity.relationships ?? {})) {
|
|
122
180
|
const compiled = compileRelationship(relName, rel, entity, config.entities[rel.entity]);
|
|
@@ -126,12 +184,39 @@ function compileEntityView(config, entityKey, options = {}) {
|
|
|
126
184
|
columns.push(compiled.refColumn);
|
|
127
185
|
}
|
|
128
186
|
}
|
|
129
|
-
|
|
130
|
-
|
|
187
|
+
return joins;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Translate a driver error from executing a compiled view into something
|
|
191
|
+
* actionable, or `undefined` when it is not one we recognise (caller rethrows).
|
|
192
|
+
*
|
|
193
|
+
* The case that matters: `WITH (security_invoker = true)` needs Postgres 15,
|
|
194
|
+
* and PG 14 rejects it with sqlstate 22023 naming a Postgres internal
|
|
195
|
+
* (`reloptions.c`) — no mention of Clivly, the option, or the version. The
|
|
196
|
+
* compiler cannot catch this itself because the host executes the SQL.
|
|
197
|
+
*/
|
|
198
|
+
function explainViewExecutionError(error) {
|
|
199
|
+
if (typeof error !== "object" || error === null) return;
|
|
200
|
+
const { code, routine } = error;
|
|
201
|
+
const message = error instanceof Error ? error.message : "";
|
|
202
|
+
if (!(code === "22023" && (routine === "parseRelOptionsInternal" || message.includes("security_invoker")))) return;
|
|
203
|
+
return "CREATE VIEW … WITH (security_invoker = true) requires Postgres 15+. Pass `securityInvoker: false` to compile without it — but note the view then runs with its owner's privileges instead of the querying role's, which bypasses row-level security (RLS) on the underlying tables. Prefer upgrading Postgres if you rely on RLS to separate tenants.";
|
|
204
|
+
}
|
|
205
|
+
function compileEntityView(config, entityKey, options = {}) {
|
|
206
|
+
const entity = config.entities[entityKey];
|
|
207
|
+
if (!entity) throw new Error(`entity "${entityKey}" is not defined`);
|
|
208
|
+
const viewName = `${options.viewPrefix ?? "crm_src_"}${entityKey}`;
|
|
209
|
+
const src = entity.source;
|
|
210
|
+
const projection = entity.projection;
|
|
211
|
+
const filterTable = projection ? BASE_REF : src;
|
|
212
|
+
const { selectItems, columns } = projection ? compileProjectionSelect(projection, SOURCE_KEY) : legacySelect(entity, src);
|
|
213
|
+
const joins = projection ? compileProjectionJoins(projection) : legacyJoins(config, entity, columns, selectItems);
|
|
214
|
+
const conditions = compileFilterConditions(filterTable, entity.filter);
|
|
215
|
+
if (options.orgScope) conditions.push(`${quoteIdent(filterTable)}.${quoteIdent(options.orgScope.column)} = ${quoteLiteral(options.orgScope.value)}`);
|
|
131
216
|
const lines = [
|
|
132
217
|
options.securityInvoker ?? true ? `CREATE OR REPLACE VIEW ${quoteIdent(viewName)} WITH (security_invoker = true) AS` : `CREATE OR REPLACE VIEW ${quoteIdent(viewName)} AS`,
|
|
133
218
|
`SELECT ${selectItems.join(", ")}`,
|
|
134
|
-
`FROM ${quoteIdent(src)}`,
|
|
219
|
+
projection ? compileProjectionFrom(projection) : `FROM ${quoteIdent(src)}`,
|
|
135
220
|
...joins
|
|
136
221
|
];
|
|
137
222
|
if (conditions.length > 0) lines.push(`WHERE ${conditions.join(" AND ")}`);
|
|
@@ -182,4 +267,4 @@ async function explainEntitiesConfig(config, run, options = {}) {
|
|
|
182
267
|
return results;
|
|
183
268
|
}
|
|
184
269
|
//#endregion
|
|
185
|
-
export { explainEntitiesConfig as i, compileEntityView as n, compileEntityViews as r, DEFAULT_VIEW_PREFIX as t };
|
|
270
|
+
export { explainViewExecutionError as a, explainEntitiesConfig as i, compileEntityView as n, compileEntityViews as r, DEFAULT_VIEW_PREFIX as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ClivlyEntitiesConfig } from "./entity-config-
|
|
1
|
+
import { a as ClivlyEntitiesConfig } from "./entity-config-fKQhimtD.mjs";
|
|
2
2
|
//#region ../core/src/view-compiler.d.ts
|
|
3
3
|
declare const DEFAULT_VIEW_PREFIX = "crm_src_";
|
|
4
4
|
interface CompileOptions {
|
|
@@ -43,6 +43,16 @@ interface CompiledView {
|
|
|
43
43
|
sql: string;
|
|
44
44
|
viewName: string;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Translate a driver error from executing a compiled view into something
|
|
48
|
+
* actionable, or `undefined` when it is not one we recognise (caller rethrows).
|
|
49
|
+
*
|
|
50
|
+
* The case that matters: `WITH (security_invoker = true)` needs Postgres 15,
|
|
51
|
+
* and PG 14 rejects it with sqlstate 22023 naming a Postgres internal
|
|
52
|
+
* (`reloptions.c`) — no mention of Clivly, the option, or the version. The
|
|
53
|
+
* compiler cannot catch this itself because the host executes the SQL.
|
|
54
|
+
*/
|
|
55
|
+
declare function explainViewExecutionError(error: unknown): string | undefined;
|
|
46
56
|
declare function compileEntityView(config: ClivlyEntitiesConfig, entityKey: string, options?: CompileOptions): CompiledView;
|
|
47
57
|
/** Compile every entity in the config into its view, in declaration order. */
|
|
48
58
|
declare function compileEntityViews(config: ClivlyEntitiesConfig, options?: CompileOptions): CompiledView[];
|
|
@@ -68,4 +78,4 @@ interface ExplainResult {
|
|
|
68
78
|
*/
|
|
69
79
|
declare function explainEntitiesConfig(config: ClivlyEntitiesConfig, run: (sql: string) => Promise<unknown>, options?: CompileOptions): Promise<ExplainResult[]>;
|
|
70
80
|
//#endregion
|
|
71
|
-
export { compileEntityView as a, ExplainResult as i, CompiledView as n, compileEntityViews as o, DEFAULT_VIEW_PREFIX as r, explainEntitiesConfig as s, CompileOptions as t };
|
|
81
|
+
export { compileEntityView as a, explainViewExecutionError as c, ExplainResult as i, CompiledView as n, compileEntityViews as o, DEFAULT_VIEW_PREFIX as r, explainEntitiesConfig as s, CompileOptions as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ClivlyEntitiesConfig } from "./entity-config-
|
|
1
|
+
import { a as ClivlyEntitiesConfig } from "./entity-config-fKQhimtD.cjs";
|
|
2
2
|
//#region ../core/src/view-compiler.d.ts
|
|
3
3
|
declare const DEFAULT_VIEW_PREFIX = "crm_src_";
|
|
4
4
|
interface CompileOptions {
|
|
@@ -43,6 +43,16 @@ interface CompiledView {
|
|
|
43
43
|
sql: string;
|
|
44
44
|
viewName: string;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Translate a driver error from executing a compiled view into something
|
|
48
|
+
* actionable, or `undefined` when it is not one we recognise (caller rethrows).
|
|
49
|
+
*
|
|
50
|
+
* The case that matters: `WITH (security_invoker = true)` needs Postgres 15,
|
|
51
|
+
* and PG 14 rejects it with sqlstate 22023 naming a Postgres internal
|
|
52
|
+
* (`reloptions.c`) — no mention of Clivly, the option, or the version. The
|
|
53
|
+
* compiler cannot catch this itself because the host executes the SQL.
|
|
54
|
+
*/
|
|
55
|
+
declare function explainViewExecutionError(error: unknown): string | undefined;
|
|
46
56
|
declare function compileEntityView(config: ClivlyEntitiesConfig, entityKey: string, options?: CompileOptions): CompiledView;
|
|
47
57
|
/** Compile every entity in the config into its view, in declaration order. */
|
|
48
58
|
declare function compileEntityViews(config: ClivlyEntitiesConfig, options?: CompileOptions): CompiledView[];
|
|
@@ -68,4 +78,4 @@ interface ExplainResult {
|
|
|
68
78
|
*/
|
|
69
79
|
declare function explainEntitiesConfig(config: ClivlyEntitiesConfig, run: (sql: string) => Promise<unknown>, options?: CompileOptions): Promise<ExplainResult[]>;
|
|
70
80
|
//#endregion
|
|
71
|
-
export { compileEntityView as a, ExplainResult as i, CompiledView as n, compileEntityViews as o, DEFAULT_VIEW_PREFIX as r, explainEntitiesConfig as s, CompileOptions as t };
|
|
81
|
+
export { compileEntityView as a, explainViewExecutionError as c, ExplainResult as i, CompiledView as n, compileEntityViews as o, DEFAULT_VIEW_PREFIX as r, explainEntitiesConfig as s, CompileOptions as t };
|
package/vite.d.cts
CHANGED
package/vite.d.mts
CHANGED
package/drizzle-B89tLo4T.mjs
DELETED
|
@@ -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 };
|
package/drizzle-CFOr9dU9.d.mts
DELETED
|
@@ -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 };
|
package/drizzle-DiReZf6d.cjs
DELETED
|
@@ -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
|
-
});
|
package/drizzle-DmeKSqeF.d.cts
DELETED
|
@@ -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 };
|
package/types-CsL0rFYh.d.cts
DELETED
|
@@ -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 };
|
package/types-CsL0rFYh.d.mts
DELETED
|
@@ -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 };
|