@clivly/sdk 0.2.0 → 0.3.0-next.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 +113 -11
- package/dist/{drizzle-meta-CAJ43cLc.mjs → drizzle-meta-DMx_9nlj.mjs} +1 -1
- package/dist/{drizzle-meta-C0T6F3vL.cjs → drizzle-meta-iAu8w1hj.cjs} +1 -1
- package/dist/drizzle.cjs +59 -2
- package/dist/drizzle.d.cts +8 -2
- package/dist/drizzle.d.mts +8 -2
- package/dist/drizzle.mjs +59 -3
- package/dist/index.cjs +306 -31
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +306 -31
- package/dist/{types-B0aSxJ6V.d.cts → namespace-probe-DFpvfl7T.d.mts} +82 -7
- package/dist/{types-DWt-ytBQ.d.mts → namespace-probe-DIBgCQca.d.cts} +82 -7
- package/dist/vite.cjs +38 -0
- package/dist/vite.d.cts +23 -0
- package/dist/vite.d.mts +23 -0
- package/dist/vite.mjs +37 -0
- package/package.json +18 -3
|
@@ -1,18 +1,39 @@
|
|
|
1
1
|
import { ClivlyEntitiesConfig } from "@clivly/core";
|
|
2
2
|
|
|
3
3
|
//#region src/drizzle-meta.d.ts
|
|
4
|
-
declare const DRIZZLE_META:
|
|
4
|
+
declare const DRIZZLE_META: "__clivly_drizzle_source_meta__";
|
|
5
5
|
interface DrizzleSourceMeta {
|
|
6
6
|
/** Drizzle property keys of every column on the source table. */
|
|
7
7
|
columnKeys: string[];
|
|
8
|
+
/** Schema-v2 typed column metadata derived from the Drizzle table. */
|
|
9
|
+
columnsMeta?: DiscoveredColumn[];
|
|
8
10
|
cursorField: string;
|
|
9
11
|
idField: string;
|
|
12
|
+
/** The backing table's real name, so discovery can key metadata by table. */
|
|
13
|
+
tableName?: string;
|
|
10
14
|
}
|
|
11
15
|
//#endregion
|
|
12
16
|
//#region src/types.d.ts
|
|
17
|
+
interface DiscoveredColumn {
|
|
18
|
+
isForeignKey?: boolean;
|
|
19
|
+
isPrimaryKey?: boolean;
|
|
20
|
+
name: string;
|
|
21
|
+
nullable?: boolean;
|
|
22
|
+
/** The column this FK points at, when it is a foreign key. */
|
|
23
|
+
references?: {
|
|
24
|
+
table: string;
|
|
25
|
+
column: string;
|
|
26
|
+
};
|
|
27
|
+
/** SQL/driver type, e.g. "text", "integer", "timestamp". */
|
|
28
|
+
type?: string;
|
|
29
|
+
}
|
|
13
30
|
interface DiscoveredTable {
|
|
14
31
|
columns: string[];
|
|
32
|
+
/** Schema-v2 typed column metadata (types, PK/FK, nullability). */
|
|
33
|
+
columnsMeta?: DiscoveredColumn[];
|
|
15
34
|
name: string;
|
|
35
|
+
/** Approximate source row count, when cheaply derivable. */
|
|
36
|
+
rowCount?: number;
|
|
16
37
|
}
|
|
17
38
|
interface ClivlySDKConfig {
|
|
18
39
|
/** Org-scoped API token (sk_live_…) from Settings → API keys. */
|
|
@@ -60,7 +81,18 @@ interface ClivlySDKConfig {
|
|
|
60
81
|
framework?: string;
|
|
61
82
|
/** Heartbeat cadence in ms. Defaults to 60s. */
|
|
62
83
|
heartbeatIntervalMs?: number;
|
|
63
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Optional live namespace probe, used on-demand by `doctor()`'s "Namespace
|
|
86
|
+
* reachable" check to verify every required source table + column is
|
|
87
|
+
* genuinely reachable. Not consulted by the heartbeat. Build one with
|
|
88
|
+
* `drizzleIntrospector(db)` from `@clivly/sdk/drizzle`.
|
|
89
|
+
*/
|
|
90
|
+
introspector?: NamespaceIntrospector;
|
|
91
|
+
/**
|
|
92
|
+
* Self-reported readiness sent on every heartbeat as-is (no live check).
|
|
93
|
+
* For a real reachability check, configure `introspector` and run
|
|
94
|
+
* `doctor()`.
|
|
95
|
+
*/
|
|
64
96
|
namespaceReady?: boolean;
|
|
65
97
|
orm?: string;
|
|
66
98
|
/**
|
|
@@ -80,6 +112,10 @@ interface ClivlySDKConfig {
|
|
|
80
112
|
source?: {
|
|
81
113
|
contacts: SyncSource;
|
|
82
114
|
companies?: SyncSource;
|
|
115
|
+
deals?: SyncSource; /** Org-defined custom objects to mirror. Each carries its object-type slug. */
|
|
116
|
+
custom?: Array<SyncSource & {
|
|
117
|
+
objectType: string;
|
|
118
|
+
}>;
|
|
83
119
|
};
|
|
84
120
|
sync?: {
|
|
85
121
|
onBoot?: boolean;
|
|
@@ -91,6 +127,29 @@ interface ClivlySDKConfig {
|
|
|
91
127
|
intervalMs?: number;
|
|
92
128
|
batchSize?: number;
|
|
93
129
|
};
|
|
130
|
+
/**
|
|
131
|
+
* The remote sync trigger: how Clivly Cloud asks this app to run a sync.
|
|
132
|
+
*
|
|
133
|
+
* Without it, cloud mode is push-only — Clivly can watch the app but can't
|
|
134
|
+
* start anything, so the dashboard's "Run sync" has nothing to call. With it,
|
|
135
|
+
* the SDK reports `url` on each heartbeat and requires every trigger request to
|
|
136
|
+
* be signed with `secret`.
|
|
137
|
+
*/
|
|
138
|
+
syncTrigger?: {
|
|
139
|
+
/**
|
|
140
|
+
* Public URL of the route where `createClivlyHandler()` is mounted, e.g.
|
|
141
|
+
* `https://app.example.com/api/clivly/tick`. Reported to Clivly on each
|
|
142
|
+
* heartbeat; a URL set in the dashboard overrides it.
|
|
143
|
+
*/
|
|
144
|
+
url?: string;
|
|
145
|
+
/**
|
|
146
|
+
* Signing secret (`whsec_…`) issued by Clivly under Integrations → Remote
|
|
147
|
+
* sync. When set, `createClivlyHandler()` rejects any request that isn't
|
|
148
|
+
* validly signed. Leave unset only if the route is already unreachable from
|
|
149
|
+
* the public internet.
|
|
150
|
+
*/
|
|
151
|
+
secret?: string;
|
|
152
|
+
};
|
|
94
153
|
/**
|
|
95
154
|
* Shared secret Clivly Cloud presents (as `Authorization: Bearer <token>`) when
|
|
96
155
|
* calling the `/clivly/auth/verify` endpoint. Required for the verify handler to
|
|
@@ -178,10 +237,16 @@ interface ClivlySDK {
|
|
|
178
237
|
*/
|
|
179
238
|
createAuthVerifyHandler(resolveUser: (req: Request) => Promise<ClivlyUser | null> | ClivlyUser | null): (req: Request) => Promise<Response>;
|
|
180
239
|
/**
|
|
181
|
-
* A fetch handler to mount at a route
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
240
|
+
* A fetch handler to mount at a route. Each request runs one `runScheduled()`
|
|
241
|
+
* and returns JSON: 200 when the sync succeeded, 500 otherwise.
|
|
242
|
+
*
|
|
243
|
+
* Two callers use it: Clivly Cloud (when someone clicks "Run sync" — those
|
|
244
|
+
* requests are HMAC-signed and carry a run id), and the host's own scheduler
|
|
245
|
+
* (Workers cron, an uptime ping — no body).
|
|
246
|
+
*
|
|
247
|
+
* When `syncTrigger.secret` is set the handler rejects unsigned or
|
|
248
|
+
* badly-signed requests with 401. When it isn't, the route stays open to
|
|
249
|
+
* anyone who can reach it — set a secret if it's publicly routable.
|
|
185
250
|
*/
|
|
186
251
|
createClivlyHandler(): (req: Request) => Promise<Response>;
|
|
187
252
|
/** Validate this setup end-to-end (read-only) before the first sync. */
|
|
@@ -200,6 +265,7 @@ interface ClivlySDK {
|
|
|
200
265
|
*/
|
|
201
266
|
runScheduled(options?: {
|
|
202
267
|
mode?: SyncMode;
|
|
268
|
+
runId?: string;
|
|
203
269
|
}): Promise<void>;
|
|
204
270
|
/**
|
|
205
271
|
* Send the initial heartbeat and start the keep-alive loop. For long-lived
|
|
@@ -218,7 +284,16 @@ interface ClivlySDK {
|
|
|
218
284
|
*/
|
|
219
285
|
sync(options?: {
|
|
220
286
|
mode?: SyncMode;
|
|
287
|
+
runId?: string;
|
|
221
288
|
}): Promise<void>;
|
|
222
289
|
}
|
|
223
290
|
//#endregion
|
|
224
|
-
|
|
291
|
+
//#region src/namespace-probe.d.ts
|
|
292
|
+
interface NamespaceIntrospector {
|
|
293
|
+
/** All base table names in the reachable schema. */
|
|
294
|
+
listTables(): Promise<string[]>;
|
|
295
|
+
/** Prove a table is genuinely selectable (SELECT ... LIMIT 1). Throws if unreachable/denied. */
|
|
296
|
+
sampleSelect(table: string): Promise<void>;
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
export { ClivlySDKConfig as a, DiscoveredTable as c, SyncSource as d, ClivlySDK as i, DoctorCheck as l, ClivlyConnectReason as n, ClivlyUser as o, ClivlyConnectResult as r, CursorStore as s, NamespaceIntrospector as t, DoctorReport as u };
|
package/dist/vite.cjs
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/vite.ts
|
|
3
|
+
/**
|
|
4
|
+
* Vite dev-server plugin that runs the Clivly SDK lifecycle for you: on server
|
|
5
|
+
* boot it calls `sdk.connect()` (for a clear status line) then `sdk.start()`
|
|
6
|
+
* (the heartbeat + sync keep-alive loop), and calls `sdk.stop()` when the dev
|
|
7
|
+
* server closes. Dev-only (`apply: "serve"`) — `start()`'s setInterval loop
|
|
8
|
+
* does not persist on serverless/edge builds, so production on Workers/Lambda
|
|
9
|
+
* should mount `sdk.createClivlyHandler()` and drive it from a cron trigger
|
|
10
|
+
* instead. See docs/guides/connecting-to-clivly-cloud.md.
|
|
11
|
+
*
|
|
12
|
+
* Vite is an optional peer dependency imported type-only (`import type`), so
|
|
13
|
+
* the built bundle carries no runtime dependency on Vite.
|
|
14
|
+
*/
|
|
15
|
+
function clivlyVite(sdk, options = {}) {
|
|
16
|
+
const label = options.name ?? "clivly";
|
|
17
|
+
return {
|
|
18
|
+
name: "clivly",
|
|
19
|
+
apply: "serve",
|
|
20
|
+
configureServer(server) {
|
|
21
|
+
const { logger } = server.config;
|
|
22
|
+
const boot = async () => {
|
|
23
|
+
const result = await sdk.connect();
|
|
24
|
+
if (result.ok) {
|
|
25
|
+
const org = result.org?.name ?? result.org?.id;
|
|
26
|
+
logger.info(`${label}: connected${org ? ` to ${org}` : ""}`);
|
|
27
|
+
} else logger.warn(`${label}: not connected (${result.reason})`);
|
|
28
|
+
await sdk.start();
|
|
29
|
+
};
|
|
30
|
+
boot().catch((error) => {
|
|
31
|
+
logger.error(`${label}: startup failed — ${error instanceof Error ? error.message : String(error)}`);
|
|
32
|
+
});
|
|
33
|
+
server.httpServer?.once("close", () => sdk.stop());
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
exports.clivlyVite = clivlyVite;
|
package/dist/vite.d.cts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { i as ClivlySDK } from "./namespace-probe-DIBgCQca.cjs";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
|
|
4
|
+
//#region src/vite.d.ts
|
|
5
|
+
interface ClivlyViteOptions {
|
|
6
|
+
/** Log prefix for Clivly's boot lines. Defaults to "clivly". */
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Vite dev-server plugin that runs the Clivly SDK lifecycle for you: on server
|
|
11
|
+
* boot it calls `sdk.connect()` (for a clear status line) then `sdk.start()`
|
|
12
|
+
* (the heartbeat + sync keep-alive loop), and calls `sdk.stop()` when the dev
|
|
13
|
+
* server closes. Dev-only (`apply: "serve"`) — `start()`'s setInterval loop
|
|
14
|
+
* does not persist on serverless/edge builds, so production on Workers/Lambda
|
|
15
|
+
* should mount `sdk.createClivlyHandler()` and drive it from a cron trigger
|
|
16
|
+
* instead. See docs/guides/connecting-to-clivly-cloud.md.
|
|
17
|
+
*
|
|
18
|
+
* Vite is an optional peer dependency imported type-only (`import type`), so
|
|
19
|
+
* the built bundle carries no runtime dependency on Vite.
|
|
20
|
+
*/
|
|
21
|
+
declare function clivlyVite(sdk: ClivlySDK, options?: ClivlyViteOptions): Plugin;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ClivlyViteOptions, clivlyVite };
|
package/dist/vite.d.mts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { i as ClivlySDK } from "./namespace-probe-DFpvfl7T.mjs";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
|
|
4
|
+
//#region src/vite.d.ts
|
|
5
|
+
interface ClivlyViteOptions {
|
|
6
|
+
/** Log prefix for Clivly's boot lines. Defaults to "clivly". */
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Vite dev-server plugin that runs the Clivly SDK lifecycle for you: on server
|
|
11
|
+
* boot it calls `sdk.connect()` (for a clear status line) then `sdk.start()`
|
|
12
|
+
* (the heartbeat + sync keep-alive loop), and calls `sdk.stop()` when the dev
|
|
13
|
+
* server closes. Dev-only (`apply: "serve"`) — `start()`'s setInterval loop
|
|
14
|
+
* does not persist on serverless/edge builds, so production on Workers/Lambda
|
|
15
|
+
* should mount `sdk.createClivlyHandler()` and drive it from a cron trigger
|
|
16
|
+
* instead. See docs/guides/connecting-to-clivly-cloud.md.
|
|
17
|
+
*
|
|
18
|
+
* Vite is an optional peer dependency imported type-only (`import type`), so
|
|
19
|
+
* the built bundle carries no runtime dependency on Vite.
|
|
20
|
+
*/
|
|
21
|
+
declare function clivlyVite(sdk: ClivlySDK, options?: ClivlyViteOptions): Plugin;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ClivlyViteOptions, clivlyVite };
|
package/dist/vite.mjs
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/vite.ts
|
|
2
|
+
/**
|
|
3
|
+
* Vite dev-server plugin that runs the Clivly SDK lifecycle for you: on server
|
|
4
|
+
* boot it calls `sdk.connect()` (for a clear status line) then `sdk.start()`
|
|
5
|
+
* (the heartbeat + sync keep-alive loop), and calls `sdk.stop()` when the dev
|
|
6
|
+
* server closes. Dev-only (`apply: "serve"`) — `start()`'s setInterval loop
|
|
7
|
+
* does not persist on serverless/edge builds, so production on Workers/Lambda
|
|
8
|
+
* should mount `sdk.createClivlyHandler()` and drive it from a cron trigger
|
|
9
|
+
* instead. See docs/guides/connecting-to-clivly-cloud.md.
|
|
10
|
+
*
|
|
11
|
+
* Vite is an optional peer dependency imported type-only (`import type`), so
|
|
12
|
+
* the built bundle carries no runtime dependency on Vite.
|
|
13
|
+
*/
|
|
14
|
+
function clivlyVite(sdk, options = {}) {
|
|
15
|
+
const label = options.name ?? "clivly";
|
|
16
|
+
return {
|
|
17
|
+
name: "clivly",
|
|
18
|
+
apply: "serve",
|
|
19
|
+
configureServer(server) {
|
|
20
|
+
const { logger } = server.config;
|
|
21
|
+
const boot = async () => {
|
|
22
|
+
const result = await sdk.connect();
|
|
23
|
+
if (result.ok) {
|
|
24
|
+
const org = result.org?.name ?? result.org?.id;
|
|
25
|
+
logger.info(`${label}: connected${org ? ` to ${org}` : ""}`);
|
|
26
|
+
} else logger.warn(`${label}: not connected (${result.reason})`);
|
|
27
|
+
await sdk.start();
|
|
28
|
+
};
|
|
29
|
+
boot().catch((error) => {
|
|
30
|
+
logger.error(`${label}: startup failed — ${error instanceof Error ? error.message : String(error)}`);
|
|
31
|
+
});
|
|
32
|
+
server.httpServer?.once("close", () => sdk.stop());
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { clivlyVite };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clivly/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-next.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Clivly SDK — connect your app to Clivly Cloud (heartbeat, discovery, auth bridge).",
|
|
@@ -26,6 +26,16 @@
|
|
|
26
26
|
"types": "./dist/drizzle.d.cts",
|
|
27
27
|
"default": "./dist/drizzle.cjs"
|
|
28
28
|
}
|
|
29
|
+
},
|
|
30
|
+
"./vite": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/vite.d.mts",
|
|
33
|
+
"default": "./dist/vite.mjs"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/vite.d.cts",
|
|
37
|
+
"default": "./dist/vite.cjs"
|
|
38
|
+
}
|
|
29
39
|
}
|
|
30
40
|
},
|
|
31
41
|
"files": [
|
|
@@ -35,14 +45,18 @@
|
|
|
35
45
|
"access": "public"
|
|
36
46
|
},
|
|
37
47
|
"dependencies": {
|
|
38
|
-
"@clivly/core": "0.
|
|
48
|
+
"@clivly/core": "0.3.0-next.1"
|
|
39
49
|
},
|
|
40
50
|
"peerDependencies": {
|
|
41
|
-
"drizzle-orm": ">=0.30"
|
|
51
|
+
"drizzle-orm": ">=0.30",
|
|
52
|
+
"vite": ">=5"
|
|
42
53
|
},
|
|
43
54
|
"peerDependenciesMeta": {
|
|
44
55
|
"drizzle-orm": {
|
|
45
56
|
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"vite": {
|
|
59
|
+
"optional": true
|
|
46
60
|
}
|
|
47
61
|
},
|
|
48
62
|
"devDependencies": {
|
|
@@ -50,6 +64,7 @@
|
|
|
50
64
|
"drizzle-orm": "^0.45.2",
|
|
51
65
|
"tsdown": "^0.21.9",
|
|
52
66
|
"typescript": "^6",
|
|
67
|
+
"vite": "^8.0.8",
|
|
53
68
|
"vitest": "^3.2.0"
|
|
54
69
|
},
|
|
55
70
|
"scripts": {
|