clivly 0.7.2 → 0.7.3

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 CHANGED
@@ -1,40 +1,34 @@
1
1
  # clivly
2
2
 
3
- Clivly's consolidated public package.
3
+ Configure and integrate [Clivly](https://clivly.com) — the CRM that lives inside
4
+ your app.
4
5
 
5
- It serves two roles:
6
+ For the full integration path, including when to use `start()` versus
7
+ `runScheduled()` / `createClivlyHandler()`, see the
8
+ [connecting to Clivly Cloud guide](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/connecting-to-clivly-cloud.md).
6
9
 
7
- - the CLI you run as `npx clivly ...`
8
- - the package that exposes the stable runtime subpaths such as `clivly/sdk`
9
-
10
- ## Install
10
+ ## Usage
11
11
 
12
12
  ```bash
13
13
  npm install clivly
14
- ```
15
-
16
- Stable releases publish on npm's `latest` tag. Use `@next` only when you are
17
- intentionally testing a prerelease build.
18
14
 
19
- This package requires Node `>=22`.
20
-
21
- ## CLI commands
22
-
23
- ```bash
24
- npx clivly init # scaffold config, route files, and .env placeholders
25
- npx clivly add widget # scaffold the chat-session route for the widget
26
- npx clivly login # pair this machine and write credentials to .env
15
+ npx clivly init # scaffold config, routes and .env, then pair this machine
16
+ npx clivly login # pair this machine and write your credentials to .env
27
17
  npx clivly status # check your setup, step by step
28
18
  npx clivly dev # tunnel localhost so remote sync can reach you
29
19
  npx clivly push-schema # report your schema to Clivly without deploying
30
20
  ```
31
21
 
32
- `ping` and `doctor` remain available as focused aliases around parts of the
33
- `status` ladder.
22
+ `ping` and `doctor` remain as aliases that run subsets of the `status` ladder.
34
23
 
35
- ## Runtime imports
24
+ Clivly's stable packages publish on npm's `latest` tag. Once installed, the
25
+ `npx clivly …` commands above use your local copy. Use `@next` only when you
26
+ are intentionally testing a prerelease cut.
36
27
 
37
- Application code should import from subpaths, not from the package root:
28
+ ## Imports
29
+
30
+ `clivly` is the consolidated public package. The CLI remains available as
31
+ `npx clivly`, while application code imports from typed subpaths:
38
32
 
39
33
  ```ts
40
34
  import { createClivlySDK, defineClivlyConfig } from "clivly/sdk";
@@ -45,43 +39,71 @@ import { createWorkOSAuthAdapter } from "clivly/auth/workos";
45
39
  import { createBetterAuthAdapter } from "clivly/auth/better-auth";
46
40
  ```
47
41
 
48
- Do **not** import application code from `clivly` (the package root). The root
49
- entry is the CLI.
50
-
51
- Provider and framework integrations use optional peer dependencies. Install only
42
+ Provider and framework integrations use optional peer dependencies.
43
+ **Supported auth providers: Clerk, WorkOS, and BetterAuth.** Install only
52
44
  what your app actually uses, such as `drizzle-orm`, `vite`, `@clerk/backend`,
53
45
  `@workos-inc/node`, or `better-auth`.
54
46
 
55
- ## `clivly init`
56
-
57
47
  `clivly init` detects your framework from `package.json`, locates your Drizzle
58
- schema, and writes:
48
+ schema, and generates a `clivly.config.ts` that maps likely contact and company
49
+ tables. The init command currently generates config for Drizzle only; Prisma and
50
+ Kysely projects should use a hand-written `fetchPage` source for now.
59
51
 
60
- - `clivly.config.ts`
61
- - the supported Clivly route files for your framework
62
- - missing `.env` placeholders
52
+ Use `--schema` when your Drizzle schema is not in a common location or in
53
+ `drizzle.config.ts`. Re-run with `--force` to overwrite an existing config.
63
54
 
64
- It currently targets Drizzle-backed integrations. Prisma and Kysely projects
65
- can still integrate, but should provide hand-written `fetchPage` sources rather
66
- than relying on the generated Drizzle path.
55
+ ### Monorepos
67
56
 
68
- Useful flags:
57
+ In a workspace, `init` reads your `pnpm-workspace.yaml` (or `workspaces` array)
58
+ and imports anything owned by a *sibling* package by **package name** rather than
59
+ by a relative path that climbs out of your app:
60
+
61
+ ```ts
62
+ import * as schema from "@acme/database"; // not "../../packages/database/src/index"
63
+ ```
64
+
65
+ `--schema` accepts a package specifier as well as a path, so all of these work:
66
+
67
+ ```bash
68
+ clivly init --schema @acme/database # the package entry
69
+ clivly init --schema @acme/database/src/schema.ts # a subpath inside it
70
+ clivly init --schema ./src/db/schema.ts # a plain path (unchanged)
71
+ ```
72
+
73
+ A real file always wins over a same-named package, so existing relative paths
74
+ keep their meaning.
69
75
 
70
76
  | Flag | Purpose |
71
77
  | --- | --- |
72
- | `--schema <path\|package>` | Where your Drizzle schema lives |
73
- | `--db-import <specifier>` | Where the Drizzle client lives when it is not beside the schema |
74
- | `--auth-import <specifier>` | Where your auth instance lives |
75
- | `--contact-table <name>` | Force the contact entity table |
76
- | `--company-table <name>` | Force the company entity table |
77
- | `--force` | Overwrite generated files / `.env` values |
78
- | `--no-login` | Skip the browser pairing step |
79
- | `--no-browser` | Print the approval URL instead of opening it |
78
+ | `--schema <path\|package>` | Where your Drizzle tables live. |
79
+ | `--db-import <specifier>` | Where the Drizzle instance lives, when it isn't beside the schema. Accepts `@acme/database#database` to name the export. |
80
+ | `--auth-import <specifier>` | Where your better-auth instance lives. Same `#exportName` form. Overrides on-disk probing, which cannot see across a package boundary. |
81
+ | `--contact-table <name>` | Use this table as the contact entity, skipping the naming heuristics. |
82
+ | `--company-table <name>` | Same for companies. |
83
+
84
+ `--contact-table` and `--company-table` accept either the SQL table name or the
85
+ name it is exported under in your schema module — whichever you have in front of
86
+ you.
87
+
88
+ ### When no contact entity can be found
80
89
 
81
- If no usable contact entity can be found, `init` writes nothing rather than
82
- generating a broken config.
90
+ `init` **writes nothing** rather than scaffolding a config that cannot compile.
91
+ Clivly needs one entity before a config will load, and it will not invent one:
92
+
93
+ ```
94
+ No usable contact entity
83
95
 
84
- Supported first-class route scaffolding today:
96
+ Tables in @acme/database:
97
+ widgets
98
+ invoices
99
+
100
+ Pick the one that holds your people and re-run:
101
+ clivly init --schema @acme/database --contact-table widgets
102
+
103
+ Nothing was written — Clivly needs one entity before a config can load.
104
+ ```
105
+
106
+ First-class route scaffolding currently exists for:
85
107
 
86
108
  - Next.js
87
109
  - TanStack Start
@@ -89,50 +111,81 @@ Supported first-class route scaffolding today:
89
111
  - Remix
90
112
  - Nuxt
91
113
 
92
- ## `clivly add widget`
114
+ Vue.js apps can still integrate Clivly, but they usually need a manual server
115
+ layer for the tick route unless they are using Nuxt.
116
+
117
+ When `init` finishes and `CLIVLY_SECRET_KEY` is still empty, it hands you straight
118
+ into `clivly login` so you don't end up staring at a blank `.env`. That step is
119
+ interactive, so it is skipped automatically when there is no TTY or when `CI` is
120
+ set — and you can always turn it off yourself:
93
121
 
94
122
  ```bash
95
- npx clivly add widget
123
+ npx clivly init --no-login # scaffold only; pair later with `clivly login`
124
+ npx clivly init --no-browser # pair, but print the URL instead of opening it
96
125
  ```
97
126
 
98
- Scaffolds the host-side widget session route that mounts
99
- `createChatSessionHandler()` from `clivly/sdk`. It is idempotent and supports
100
- `--dry-run` and `--force`.
101
-
102
127
  ## `clivly login`
103
128
 
104
129
  ```bash
105
130
  npx clivly login [--force] [--rotate] [--api-url <url>] [--no-browser]
106
131
  ```
107
132
 
108
- Pairs this machine with a Clivly workspace and writes:
109
-
110
- - `CLIVLY_SECRET_KEY`
111
- - `CLIVLY_SYNC_TRIGGER_SECRET`
112
-
113
- into your project's `.env`.
114
-
115
- The approval URL is always printed, so headless or SSH sessions can still be
116
- approved in another browser.
117
-
118
- Notes:
119
-
120
- - `--force` overwrites existing real values
121
- - `--rotate` rotates the remote-sync trigger secret instead of revealing the
122
- current one
123
- - pairing is feature-flagged server-side with `CLIVLY_CLI_PAIRING_ENABLED`
124
-
125
- If pairing is unavailable, you can still set credentials manually and then run
126
- `clivly status`.
133
+ Pairs this machine with a Clivly workspace and writes `CLIVLY_SECRET_KEY` and
134
+ `CLIVLY_SYNC_TRIGGER_SECRET` into your project's `.env`. It creates a pairing
135
+ session, prints (and by default opens) an approval link, and waits while you
136
+ approve it in a signed-in browser. The approval link is always printed, so an
137
+ SSH or headless session can be approved by opening the link elsewhere.
138
+
139
+ - `--no-browser` — print the approval URL without opening a browser.
140
+ - `--force` — overwrite `.env` values that already have a real value. Without
141
+ it, existing values are kept and reported as skipped; an empty placeholder
142
+ (`CLIVLY_SECRET_KEY=`) is always filled in.
143
+ - `--rotate` — rotate the workspace's remote-sync trigger secret instead of
144
+ revealing the current one. Your already-deployed host app will stop receiving
145
+ sync triggers until you redeploy it with the new secret.
146
+
147
+ Before anything is written, the CLI prints which workspace approved the pairing
148
+ and asks you to confirm. Declining writes nothing and exits non-zero. In a
149
+ non-interactive run (no TTY, or `CI` set) the workspace is still printed but
150
+ you are not prompted, so scripted pairing cannot hang.
151
+
152
+ The pairing endpoints are feature-flagged server-side
153
+ (`CLIVLY_CLI_PAIRING_ENABLED`); if the backend you point at has not enabled
154
+ them, `clivly login` says so and exits non-zero.
155
+
156
+ **Clivly Cloud has pairing enabled**, so `clivly login` is the normal path there.
157
+ The flag defaults to `false`, so a self-hosted backend must opt in.
158
+
159
+ ### Manual credential path
160
+
161
+ If pairing is unavailable — a self-hosted backend with the flag off, or a
162
+ restricted environment — every credential can be set by hand. Nothing about the
163
+ CLI requires pairing.
164
+
165
+ | Value | Where to get it | Notes |
166
+ | --- | --- | --- |
167
+ | `CLIVLY_SECRET_KEY` | Dashboard → **Settings → API keys** → Create | **Shown once.** Copy it immediately; you cannot retrieve it later, only regenerate. Regenerating **revokes the previous key**, so redeploy after rotating. The legacy name `CLIVLY_API_KEY` is still accepted as a fallback. |
168
+ | `CLIVLY_SYNC_TRIGGER_SECRET` | Dashboard → **Integrations → Remote sync** | Must match the value in your app's env exactly. A mismatch surfaces as a `401` on the signed trigger. |
169
+ | `CLIVLY_SYNC_TRIGGER_URL` | Your own deployment | The public URL of your mounted tick route, e.g. `https://app.example.com/api/clivly/tick`. Optional until you deploy — push-only setups can leave it unset. |
170
+
171
+ Write them into the `.env` of the package that imports `clivly`, then re-run
172
+ `clivly status` to confirm each rung goes green.
173
+
174
+ > **Running your own Clivly backend?** `CLIVLY_TRIGGER_SECRET_WRAPPING_KEY` (a
175
+ > 32-byte hex key) is a **hard production prerequisite** for pairing. The
176
+ > trigger secret is stored encrypted with it, so without the key set on the
177
+ > server, `clivly login` fails with a 500 at the moment it would hand over
178
+ > credentials. Set it before enabling `CLIVLY_CLI_PAIRING_ENABLED`.
127
179
 
128
180
  ## `clivly status`
129
181
 
130
182
  ```bash
131
- npx clivly status [--verbose] [--config <path>] [--env-file <path>]
183
+ npx clivly status [--verbose] [--config <path>]
132
184
  ```
133
185
 
134
- Walks the setup one rung at a time: credentials, config, schema, sources, and
135
- connectivity. This is the main diagnostic command for integration issues.
186
+ Walks your setup one rung at a time — credentials, config, schema, sources,
187
+ connectivity — and stops at the first thing that isn't ready, telling you what
188
+ to do about it. This is the command to reach for when something isn't working.
136
189
 
137
190
  ## `clivly dev`
138
191
 
@@ -141,49 +194,52 @@ npx clivly dev [--port <n>] [--api-url <url>] [--route-path <path>] [-- <cmd>]
141
194
  ```
142
195
 
143
196
  Opens a `cloudflared` tunnel to your local app and registers it with Clivly for
144
- the lifetime of the session, so remote sync can reach `localhost` during local
145
- development. The override is cleared on exit.
146
-
147
- Requires:
197
+ the length of the session, so remote sync can reach `localhost` while you
198
+ develop. Your dev server is detected from `package.json` scripts, or pass it
199
+ explicitly after `--`. Needs `cloudflared` on `PATH` and `CLIVLY_SECRET_KEY` set.
200
+ The override is cleared when the process exits; remote sync is otherwise
201
+ deploy-only.
148
202
 
149
- - `cloudflared` on `PATH`
150
- - `CLIVLY_SECRET_KEY` set
203
+ ## `clivly ping` / `clivly doctor`
151
204
 
152
- ## `clivly push-schema`
205
+ `clivly ping` reads `CLIVLY_SECRET_KEY` from the environment, sends one heartbeat, and prints a clear ✅/❌ with the resolved org or the failure reason — so you can confirm a connection from the terminal without writing any code. Point it at a non-default backend with `--api-url <url>` (or `CLIVLY_API_URL`).
153
206
 
154
207
  ```bash
155
- npx clivly push-schema [--config <path>]
208
+ CLIVLY_SECRET_KEY=sk_live_… npx clivly ping
209
+ #
210
+ # Clivly ping
211
+ # ✅ Connected to Clivly
212
+ # Org: Acme (org_1)
156
213
  ```
157
214
 
158
- Reports your discovered schema to Clivly without waiting for a deployed app to
159
- heartbeat it first.
160
-
161
- ## `clivly ping` / `clivly doctor`
162
-
163
- `clivly ping` sends one heartbeat and prints a terse pass/fail result.
215
+ `clivly doctor` loads your config and runs the same read-only checks as
216
+ `await clivly.doctor()`: API key, entity config, sources, Drizzle cursor/id
217
+ columns, sample fetch, and heartbeat.
164
218
 
165
- `clivly doctor` loads your config and runs the same read-only checks exposed by
166
- `await clivly.doctor()`.
219
+ ```bash
220
+ npx clivly doctor
221
+ npx clivly doctor --config ./apps/web/clivly.config.ts
222
+ ```
167
223
 
168
224
  ## Telemetry
169
225
 
170
- Clivly collects no telemetry. The CLI makes network requests only to the
171
- Clivly API you point it at, and only to do the work you asked for: pairing,
172
- heartbeats, schema pushes, status checks, and tunnel override registration.
173
-
174
- See the telemetry section in:
175
- [SECURITY.md](https://github.com/amani-joseph/clivly.com/blob/master/SECURITY.md#telemetry)
226
+ **Clivly collects no telemetry.** The CLI makes network requests only to the
227
+ Clivly API you point it at, and only to do what you asked: pairing, heartbeats,
228
+ schema pushes, and status checks. No usage analytics, no crash reporting, no
229
+ phone-home. See [SECURITY.md](https://github.com/amani-joseph/clivly.com/blob/master/SECURITY.md#telemetry).
176
230
 
177
231
  ## More docs
178
232
 
179
- - Cloud onboarding guide:
180
- [Connecting to Clivly Cloud](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/connecting-to-clivly-cloud.md)
181
- - Chat widget guide:
182
- [Adding the chat widget](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/adding-the-chat-widget.md)
233
+ - Onboarding guide:
234
+ [connecting to Clivly Cloud](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/connecting-to-clivly-cloud.md)
235
+ - Adding the chat widget:
236
+ [guide](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/adding-the-chat-widget.md)
237
+ - Security policy:
238
+ [SECURITY.md](https://github.com/amani-joseph/clivly.com/blob/master/SECURITY.md)
183
239
  - SDK docs:
184
- [packages/sdk/README.md](https://github.com/amani-joseph/clivly.com/blob/master/packages/sdk/README.md)
240
+ [`@clivly/sdk` README](https://github.com/amani-joseph/clivly.com/blob/master/packages/sdk/README.md)
185
241
  - Release notes:
186
- [CHANGELOG.md](https://github.com/amani-joseph/clivly.com/blob/master/CHANGELOG.md)
242
+ [CHANGELOG](https://github.com/amani-joseph/clivly.com/blob/master/CHANGELOG.md)
187
243
 
188
244
  ## License
189
245
 
package/drizzle.d.cts CHANGED
@@ -1,14 +1,6 @@
1
1
  import { t as discoverFromDrizzle } from "./drizzle-DmeKSqeF.cjs";
2
- import { n as SyncSource } from "./types-CsL0rFYh.cjs";
2
+ import { m as SyncSource, t as NamespaceIntrospector } from "./namespace-probe-DRzOtaRT.cjs";
3
3
  import { Table } from "drizzle-orm";
4
- //#region ../sdk/src/namespace-probe.d.ts
5
- interface NamespaceIntrospector {
6
- /** All base table names in the reachable schema. */
7
- listTables(): Promise<string[]>;
8
- /** Prove a table is genuinely selectable (SELECT ... LIMIT 1). Throws if unreachable/denied. */
9
- sampleSelect(table: string): Promise<void>;
10
- }
11
- //#endregion
12
4
  //#region ../sdk/src/drizzle.d.ts
13
5
  interface DrizzleDb {
14
6
  select: (...args: any[]) => any;
package/drizzle.d.mts CHANGED
@@ -1,14 +1,6 @@
1
1
  import { t as discoverFromDrizzle } from "./drizzle-CFOr9dU9.mjs";
2
- import { n as SyncSource } from "./types-CsL0rFYh.mjs";
2
+ import { m as SyncSource, t as NamespaceIntrospector } from "./namespace-probe-B4WE45TH.mjs";
3
3
  import { Table } from "drizzle-orm";
4
- //#region ../sdk/src/namespace-probe.d.ts
5
- interface NamespaceIntrospector {
6
- /** All base table names in the reachable schema. */
7
- listTables(): Promise<string[]>;
8
- /** Prove a table is genuinely selectable (SELECT ... LIMIT 1). Throws if unreachable/denied. */
9
- sampleSelect(table: string): Promise<void>;
10
- }
11
- //#endregion
12
4
  //#region ../sdk/src/drizzle.d.ts
13
5
  interface DrizzleDb {
14
6
  select: (...args: any[]) => any;