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/README.md CHANGED
@@ -1,91 +1,158 @@
1
1
  # clivly
2
2
 
3
- Configure and integrate [Clivly](https://clivly.com) — the CRM that lives inside
4
- your app.
3
+ The consolidated public package for [Clivly](https://clivly.com) — the CRM that
4
+ lives inside your app. It is two things in one install:
5
5
 
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
+ - **A CLI** (`npx clivly …`) that scaffolds your integration, pairs your machine
7
+ with a workspace, and diagnoses the setup.
8
+ - **A runtime**, imported from typed subpaths (`clivly/sdk`, `clivly/drizzle`,
9
+ `clivly/vite`, `clivly/auth/*`).
9
10
 
10
- ## Usage
11
+ > **The canonical end-to-end integration guide is
12
+ > [Connecting to Clivly Cloud](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/connecting-to-clivly-cloud.md).**
13
+ > This README is the command-level reference.
14
+
15
+ ## Prerequisites
16
+
17
+ | Requirement | Version / note |
18
+ | --- | --- |
19
+ | Node.js | **≥ 22** |
20
+ | An existing app | The CLI scaffolds into a project you already have |
21
+ | Drizzle ORM | Required for `clivly init` to generate a config. Prisma/Kysely/raw-SQL projects hand-write a `fetchPage` source instead |
22
+ | `cloudflared` on `PATH` | Only for `clivly dev` |
23
+
24
+ ## Installation
11
25
 
12
26
  ```bash
13
27
  npm install clivly
28
+ ```
29
+
30
+ Published on npm's `latest` tag. Once installed, `npx clivly …` uses your local
31
+ copy rather than re-fetching. Use `@next` only when deliberately testing a
32
+ prerelease cut.
14
33
 
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
17
- npx clivly status # check your setup, step by step
18
- npx clivly dev # tunnel localhost so remote sync can reach you
19
- npx clivly push-schema # report your schema to Clivly without deploying
34
+ ## Five-minute quick start
35
+
36
+ ```bash
37
+ npm install clivly
38
+ npx clivly init # scaffold config + routes + .env, then pair this machine
39
+ npx clivly status # check every setup step until they all pass
20
40
  ```
21
41
 
22
- `ping` and `doctor` remain as aliases that run subsets of the `status` ladder.
42
+ `clivly init` writes exactly three files (plus `.env` keys) — a
43
+ `clivly.config.ts` you own, and two route files Clivly owns. It creates no
44
+ database tables and does not modify your ORM schema.
23
45
 
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.
46
+ ---
27
47
 
28
- ## Imports
48
+ ## Commands
29
49
 
30
- `clivly` is the consolidated public package. The CLI remains available as
31
- `npx clivly`, while application code imports from typed subpaths:
50
+ | Command | What it does |
51
+ | --- | --- |
52
+ | [`clivly init`](#clivly-init) | Scaffold config, routes and env placeholders for your app |
53
+ | [`clivly login`](#clivly-login) | Pair this machine and write credentials to your env file |
54
+ | [`clivly status`](#clivly-status) | Check your setup, step by step. Read-only |
55
+ | [`clivly add widget`](#clivly-add-widget) | Scaffold the chat-session route |
56
+ | [`clivly push-schema`](#clivly-push-schema) | Report your schema to Clivly without deploying |
57
+ | [`clivly dev`](#clivly-dev) | Tunnel localhost so remote sync can reach you |
58
+ | `clivly --version` | Print the installed `clivly` version |
59
+ | [`clivly ping` / `connect` / `doctor`](#deprecated-aliases) | Deprecated aliases running parts of `status` |
32
60
 
33
- ```ts
34
- import { createClivlySDK, defineClivlyConfig } from "clivly/sdk";
35
- import { fromDrizzle } from "clivly/drizzle";
36
- import { clivlyVite } from "clivly/vite";
37
- import { createClerkAuthAdapter } from "clivly/auth/clerk";
38
- import { createWorkOSAuthAdapter } from "clivly/auth/workos";
39
- import { createBetterAuthAdapter } from "clivly/auth/better-auth";
61
+ Every command accepts `--help` (or `-h`), which **describes without acting**.
62
+
63
+ ---
64
+
65
+ ### `clivly init`
66
+
67
+ ```bash
68
+ npx clivly init [--force] [--dry-run] [--diff] [--yes] [--no-login] [--no-browser]
69
+ [--schema <path|package>] [--db-import <specifier>]
70
+ [--auth-import <specifier>] [--contact-table <table>]
71
+ [--company-table <table>]
40
72
  ```
41
73
 
42
- Provider and framework integrations use optional peer dependencies.
43
- **Supported auth providers: Clerk, WorkOS, and BetterAuth.** Install only
44
- what your app actually uses, such as `drizzle-orm`, `vite`, `@clerk/backend`,
45
- `@workos-inc/node`, or `better-auth`.
74
+ Detects your framework, ORM, auth adapter and app layout, then scaffolds:
75
+
76
+ | File | Owned by Clivly |
77
+ | --- | --- |
78
+ | `clivly.config.ts` | No — yours to edit |
79
+ | The tick route for your framework | Yes — `--force` to overwrite |
80
+ | The auth-verify route for your framework | Yes — `--force` to overwrite |
81
+
82
+ Plus `CLIVLY_SECRET_KEY`, `CLIVLY_SYNC_TRIGGER_URL` and
83
+ `CLIVLY_SYNC_TRIGGER_SECRET` placeholders in your env file.
84
+
85
+ | Flag | Purpose |
86
+ | --- | --- |
87
+ | `--dry-run` | Show what would be written; write nothing |
88
+ | `--diff` | Show a diff for files that already exist |
89
+ | `--force` | Overwrite the files Clivly owns |
90
+ | `--yes` | Skip prompts |
91
+ | `--no-login` | Skip browser pairing |
92
+ | `--no-browser` | Pair, but print the URL instead of opening it |
93
+ | `--schema <path\|package>` | Where your Drizzle tables live |
94
+ | `--db-import <specifier>` | Where the Drizzle instance lives, when it is not beside the schema. Accepts `@acme/database#database` to name the export |
95
+ | `--auth-import <specifier>` | Where your better-auth instance lives. Same `#exportName` form. Overrides on-disk probing, which cannot see across a package boundary |
96
+ | `--contact-table <name>` | Use this table as the contact entity, skipping the naming heuristics |
97
+ | `--company-table <name>` | Same for companies |
98
+
99
+ `--contact-table` and `--company-table` accept either the SQL table name or the
100
+ name it is exported under in your schema module — whichever you have in front of
101
+ you.
102
+
103
+ When `init` finishes and `CLIVLY_SECRET_KEY` is still empty, it hands you
104
+ straight into `clivly login` so you don't end up staring at a blank env file.
105
+ That step is interactive, so it is skipped automatically when there is no TTY or
106
+ when `CI` is set.
107
+
108
+ #### Framework support
109
+
110
+ Route scaffolding exists for these five. Anywhere else, mount the handler
111
+ yourself — it is a plain `(Request) => Promise<Response>`.
112
+
113
+ | Framework | Tick route written |
114
+ | --- | --- |
115
+ | Next.js | `app/api/clivly/tick/route.ts` (or `src/app/…`) |
116
+ | TanStack Start | `src/routes/api/clivly/tick.ts` |
117
+ | SvelteKit | `src/routes/api/clivly/tick/+server.ts` |
118
+ | Remix | `app/routes/api.clivly.tick.ts` |
119
+ | Nuxt | `server/api/clivly/tick.ts` |
120
+
121
+ Plain Vue apps can still integrate Clivly, but they need a manual server layer
122
+ for the tick route unless they are on Nuxt.
123
+
124
+ #### ORM support
46
125
 
47
- `clivly init` detects your framework from `package.json`, locates your Drizzle
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.
126
+ `init` generates a config for **Drizzle only**. Prisma and Kysely projects
127
+ integrate through a hand-written `fetchPage` source — see the
128
+ [Non-Drizzle sources](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/connecting-to-clivly-cloud.md#non-drizzle-sources)
129
+ section of the guide.
51
130
 
52
131
  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.
132
+ `drizzle.config.ts`.
54
133
 
55
- ### Monorepos
134
+ #### Monorepos
56
135
 
57
136
  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:
137
+ and imports anything owned by a *sibling* package by **package name** rather
138
+ than by a relative path that climbs out of your app:
60
139
 
61
140
  ```ts
62
141
  import * as schema from "@acme/database"; // not "../../packages/database/src/index"
63
142
  ```
64
143
 
65
- `--schema` accepts a package specifier as well as a path, so all of these work:
144
+ `--schema` accepts a package specifier as well as a path:
66
145
 
67
146
  ```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)
147
+ npx clivly init --schema @acme/database # the package entry
148
+ npx clivly init --schema @acme/database/src/schema.ts # a subpath inside it
149
+ npx clivly init --schema ./src/db/schema.ts # a plain path
71
150
  ```
72
151
 
73
152
  A real file always wins over a same-named package, so existing relative paths
74
153
  keep their meaning.
75
154
 
76
- | Flag | Purpose |
77
- | --- | --- |
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
155
+ #### When no contact entity can be found
89
156
 
90
157
  `init` **writes nothing** rather than scaffolding a config that cannot compile.
91
158
  Clivly needs one entity before a config will load, and it will not invent one:
@@ -103,73 +170,67 @@ No usable contact entity
103
170
  Nothing was written — Clivly needs one entity before a config can load.
104
171
  ```
105
172
 
106
- First-class route scaffolding currently exists for:
173
+ ---
107
174
 
108
- - Next.js
109
- - TanStack Start
110
- - SvelteKit
111
- - Remix
112
- - Nuxt
113
-
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:
121
-
122
- ```bash
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
125
- ```
126
-
127
- ## `clivly login`
175
+ ### `clivly login`
128
176
 
129
177
  ```bash
130
178
  npx clivly login [--force] [--rotate] [--api-url <url>] [--no-browser]
131
179
  ```
132
180
 
133
181
  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
182
+ `CLIVLY_SYNC_TRIGGER_SECRET` into your project's env file. It creates a pairing
135
183
  session, prints (and by default opens) an approval link, and waits while you
136
184
  approve it in a signed-in browser. The approval link is always printed, so an
137
185
  SSH or headless session can be approved by opening the link elsewhere.
138
186
 
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.
187
+ | Flag | Effect |
188
+ | --- | --- |
189
+ | `--no-browser` | Print the approval URL without opening a browser |
190
+ | `--force` | Overwrite env values that already have a real value. Without it, existing values are kept and reported as skipped; an empty placeholder (`CLIVLY_SECRET_KEY=`) is always filled in |
191
+ | `--rotate` | Rotate the workspace's remote-sync trigger secret instead of revealing the current one. **Your already-deployed app stops receiving sync triggers until you redeploy it with the new secret** |
192
+ | `--api-url <url>` | Point at a non-default backend |
146
193
 
147
194
  Before anything is written, the CLI prints which workspace approved the pairing
148
195
  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.
196
+ non-interactive run (no TTY, or `CI` set) the workspace is still printed but you
197
+ are not prompted, so scripted pairing cannot hang.
151
198
 
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.
199
+ #### Which env file gets written
200
+
201
+ The CLI follows your framework's convention. This is not cosmetic on Workers:
202
+ wrangler reads `.dev.vars` and nothing else, so credentials written to `.env`
203
+ would never load.
155
204
 
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.
205
+ | Framework | Env file |
206
+ | --- | --- |
207
+ | Next.js | `.env.local` |
208
+ | TanStack Start, SvelteKit, Remix, Nuxt | `.env` |
209
+ | Hono on Cloudflare Workers | `.dev.vars` |
210
+ | Anything else | `.env` |
158
211
 
159
- ### Manual credential path
212
+ #### Pairing availability
160
213
 
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.
214
+ The pairing endpoints are feature-flagged server-side
215
+ (`CLIVLY_CLI_PAIRING_ENABLED`). **Clivly Cloud has pairing enabled**, so
216
+ `clivly login` is the normal path there. The flag defaults to `false`, so a
217
+ self-hosted backend must opt in — otherwise `clivly login` says so and exits
218
+ non-zero.
219
+
220
+ #### Manual credential path
221
+
222
+ If pairing is unavailable, every credential can be set by hand. Nothing about
223
+ the CLI requires pairing.
164
224
 
165
225
  | Value | Where to get it | Notes |
166
226
  | --- | --- | --- |
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. |
227
+ | `CLIVLY_SECRET_KEY` | Dashboard → **Connect app**, or **Settings → API keys** | **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 |
228
+ | `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 |
229
+ | `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 |
230
+ | `CLIVLY_PUBLISHABLE_KEY` | Same place as the secret key | Only needed for the chat widget. Safe to expose in client code |
170
231
 
171
- Write them into the `.env` of the package that imports `clivly`, then re-run
172
- `clivly status` to confirm each rung goes green.
232
+ Write them into the env file of the package that imports `clivly`, then re-run
233
+ `clivly status` to confirm each step goes green.
173
234
 
174
235
  > **Running your own Clivly backend?** `CLIVLY_TRIGGER_SECRET_WRAPPING_KEY` (a
175
236
  > 32-byte hex key) is a **hard production prerequisite** for pairing. The
@@ -177,17 +238,71 @@ Write them into the `.env` of the package that imports `clivly`, then re-run
177
238
  > server, `clivly login` fails with a 500 at the moment it would hand over
178
239
  > credentials. Set it before enabling `CLIVLY_CLI_PAIRING_ENABLED`.
179
240
 
180
- ## `clivly status`
241
+ ---
242
+
243
+ ### `clivly status`
181
244
 
182
245
  ```bash
183
- npx clivly status [--verbose] [--config <path>]
246
+ npx clivly status [--verbose] [--config <path>] [--env-file <path>]
184
247
  ```
185
248
 
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.
249
+ Walks your setup one step at a time and stops at the first thing that isn't
250
+ ready, telling you what to do about it. **This is the command to reach for when
251
+ something isn't working.** It is read-only and writes nothing.
189
252
 
190
- ## `clivly dev`
253
+ The ladder: credential → Clivly reachable → `clivly.config` loads →
254
+ `clivly.config` is edge-safe → setup checks → sync trigger URL.
255
+
256
+ | Flag | Effect |
257
+ | --- | --- |
258
+ | `--verbose` | Show every check, including those that passed |
259
+ | `--config <path>` | Path to `clivly.config.ts` (needed in a monorepo) |
260
+ | `--env-file <path>` | Extra env file to load. Repeatable; later files win |
261
+
262
+ ```bash
263
+ npx clivly status --config ./apps/web/clivly.config.ts
264
+ npx clivly status --env-file ../server/.env
265
+ ```
266
+
267
+ Env precedence, strongest first: **real environment → `--env-file` / the
268
+ `envFiles` array in `clivly.cli.ts` → `.env.local` → `.env`**.
269
+
270
+ ---
271
+
272
+ ### `clivly add widget`
273
+
274
+ ```bash
275
+ npx clivly add widget [--force] [--dry-run]
276
+ ```
277
+
278
+ Writes the route that mints chat-widget sessions, for your detected framework
279
+ (e.g. `app/api/clivly/widget/session/route.ts` on Next.js). Idempotent.
280
+
281
+ It creates **no widget record** — that lives in the Clivly dashboard under
282
+ **Settings → Chat widget**. See
283
+ [Adding the chat widget](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/adding-the-chat-widget.md)
284
+ for the full flow.
285
+
286
+ | Flag | Effect |
287
+ | --- | --- |
288
+ | `--dry-run` | Show what would be written; write nothing |
289
+ | `--force` | Overwrite the route if it already exists |
290
+
291
+ ---
292
+
293
+ ### `clivly push-schema`
294
+
295
+ ```bash
296
+ npx clivly push-schema [--config <path>]
297
+ ```
298
+
299
+ Sends your discovered tables and columns to Clivly so the dashboard can offer
300
+ them for mapping — without deploying your app. Reads your config; writes nothing
301
+ locally. **Table and column names only; never row data.**
302
+
303
+ ---
304
+
305
+ ### `clivly dev`
191
306
 
192
307
  ```bash
193
308
  npx clivly dev [--port <n>] [--api-url <url>] [--route-path <path>] [-- <cmd>]
@@ -196,50 +311,131 @@ npx clivly dev [--port <n>] [--api-url <url>] [--route-path <path>] [-- <cmd>]
196
311
  Opens a `cloudflared` tunnel to your local app and registers it with Clivly for
197
312
  the length of the session, so remote sync can reach `localhost` while you
198
313
  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
314
+ explicitly after `--`. Needs `cloudflared` on `PATH` and `CLIVLY_SECRET_KEY`
315
+ set. The override is cleared when the process exits; remote sync is otherwise
201
316
  deploy-only.
202
317
 
203
- ## `clivly ping` / `clivly doctor`
318
+ ```bash
319
+ npx clivly dev --port 3000 -- npm run dev
320
+ ```
321
+
322
+ It also watches `clivly.config.ts` and tells you when it changes. It cannot
323
+ reload it for you — the config belongs to your app's process, not to the CLI.
324
+
325
+ If registration fails, the warning names the cause: an invalid key, a backend
326
+ without the endpoint enabled, an HTTP status Clivly returned, or a genuine
327
+ network failure. Your app keeps running either way, and outbound sync (your app
328
+ → Clivly) is unaffected — only dashboard-triggered sync needs the tunnel.
329
+
330
+ | Flag | Effect |
331
+ | --- | --- |
332
+ | `--port <n>` | Local port your app listens on |
333
+ | `--route-path <path>` | Path to your mounted tick route |
334
+ | `--api-url <url>` | Point at a non-default backend |
335
+
336
+ ---
337
+
338
+ ### Deprecated aliases
339
+
340
+ `ping`, `connect` and `doctor` each run part of the `status` ladder. They still
341
+ work, and are kept because output and docs have recommended them — but prefer
342
+ `clivly status`, which runs the whole ladder and tells you which step you are on.
343
+
344
+ | Alias | Equivalent scope |
345
+ | --- | --- |
346
+ | `clivly ping` | Credential + reachability |
347
+ | `clivly connect` | The above, plus config and trigger URL |
348
+ | `clivly doctor` | Config, setup checks and edge safety |
204
349
 
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`).
350
+ Each prints a deprecation notice, then the steps it covers, renumbered to its own
351
+ scope:
206
352
 
207
353
  ```bash
208
- CLIVLY_SECRET_KEY=sk_live_… npx clivly ping
209
- #
210
- # Clivly ping
211
- # ✅ Connected to Clivly
212
- # Org: Acme (org_1)
354
+ $ npx clivly ping
355
+ `clivly ping` is a deprecated alias that runs part of `clivly status`. Prefer `clivly status`.
356
+
357
+ Clivly status
358
+ ✅ Step 1 of 2 · API key present — Secret key is set.
359
+ ✅ Step 2 of 2 · Clivly reachable — Reached org: acme (org_1)
213
360
  ```
214
361
 
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.
362
+ `clivly doctor` runs the same read-only checks as `await clivly.doctor()` in
363
+ code: API key present, entities configured, sources configured, concept
364
+ coverage, Drizzle cursor/id columns, sample fetch, mapping dry-run,
365
+ custom-object slugs, heartbeat, and namespace reachability.
218
366
 
219
- ```bash
220
- npx clivly doctor
221
- npx clivly doctor --config ./apps/web/clivly.config.ts
367
+ ---
368
+
369
+ ## Runtime imports
370
+
371
+ `clivly` is the consolidated public package. Application code imports from typed
372
+ subpaths:
373
+
374
+ ```ts
375
+ import { createClivlySDK, defineClivlyConfig } from "clivly/sdk";
376
+ import { fromDrizzle, discoverFromDrizzle } from "clivly/drizzle";
377
+ import { clivlyVite } from "clivly/vite";
378
+ import { createClerkAuthAdapter } from "clivly/auth/clerk";
379
+ import { createWorkOSAuthAdapter } from "clivly/auth/workos";
380
+ import { createBetterAuthAdapter } from "clivly/auth/better-auth";
222
381
  ```
223
382
 
383
+ > **Never `import` from the bare `clivly` specifier.** The package root is the
384
+ > CLI binary — it imports `node:fs` and `node:child_process` at module scope, so
385
+ > importing it from app code drags the whole CLI into your bundle and throws at
386
+ > import time on Workers and other edge runtimes.
387
+
388
+ Provider and framework integrations use **optional peer dependencies**. Install
389
+ only what your app actually uses:
390
+
391
+ | Subpath | Peer dependency |
392
+ | --- | --- |
393
+ | `clivly/drizzle` | `drizzle-orm` |
394
+ | `clivly/vite` | `vite` |
395
+ | `clivly/auth/clerk` | `@clerk/backend` |
396
+ | `clivly/auth/workos` | `@workos-inc/node` |
397
+ | `clivly/auth/better-auth` | none — you pass your own `betterAuth({...})` instance |
398
+
399
+ `clivly/core/*` is deprecated in favour of `clivly/internal/*`. It still
400
+ resolves, and emits a one-time `process.emitWarning` naming the replacement (so
401
+ it stays off stdout and cannot corrupt machine-readable CLI output). See
402
+ [STABILITY.md](https://github.com/amani-joseph/clivly.com/blob/master/STABILITY.md).
403
+
404
+ ---
405
+
406
+ ## Common errors
407
+
408
+ | Symptom | Fix |
409
+ | --- | --- |
410
+ | Generated code doesn't match these docs | `npx clivly --version` — an older installed version is the usual cause |
411
+ | `init` refuses to write, "No usable contact entity" | Pass `--contact-table <name>` |
412
+ | `init` cannot find your schema | Pass `--schema <path\|package>` |
413
+ | `init` scaffolded a `db` import that doesn't resolve | The probe cannot evaluate a db module that throws without `DATABASE_URL`. Fix the `TODO(clivly)` import path it left, or pass `--db-import` |
414
+ | `clivly login` exits non-zero, pairing unavailable | The backend has `CLIVLY_CLI_PAIRING_ENABLED` off. Use the manual credential path above |
415
+ | `clivly dev` cannot start | Install `cloudflared`, or set `CLIVLY_SYNC_TRIGGER_URL` to a tunnel you run yourself |
416
+ | Credentials written but the app never loads them | Wrong env file for your framework — see the table under `clivly login` |
417
+
418
+ The full troubleshooting table is in the
419
+ [integration guide](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/connecting-to-clivly-cloud.md#8-common-errors-and-troubleshooting).
420
+
421
+ ---
422
+
224
423
  ## Telemetry
225
424
 
226
425
  **Clivly collects no telemetry.** The CLI makes network requests only to the
227
426
  Clivly API you point it at, and only to do what you asked: pairing, heartbeats,
228
427
  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).
230
-
231
- ## More docs
232
-
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)
239
- - SDK docs:
240
- [`@clivly/sdk` README](https://github.com/amani-joseph/clivly.com/blob/master/packages/sdk/README.md)
241
- - Release notes:
242
- [CHANGELOG](https://github.com/amani-joseph/clivly.com/blob/master/CHANGELOG.md)
428
+ phone-home. See
429
+ [SECURITY.md](https://github.com/amani-joseph/clivly.com/blob/master/SECURITY.md#telemetry).
430
+
431
+ ## Related documentation
432
+
433
+ - **[Connecting to Clivly Cloud](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/connecting-to-clivly-cloud.md)** — the canonical end-to-end guide
434
+ - [Adding the chat widget](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/adding-the-chat-widget.md)
435
+ - [`@clivly/sdk` README](https://github.com/amani-joseph/clivly.com/blob/master/packages/sdk/README.md) — the runtime API surface
436
+ - [STABILITY.md](https://github.com/amani-joseph/clivly.com/blob/master/STABILITY.md) — import tiers
437
+ - [SECURITY.md](https://github.com/amani-joseph/clivly.com/blob/master/SECURITY.md)
438
+ - [CHANGELOG.md](https://github.com/amani-joseph/clivly.com/blob/master/CHANGELOG.md)
243
439
 
244
440
  ## License
245
441
 
package/core-drizzle.cjs CHANGED
@@ -1,8 +1,10 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
3
- const require_drizzle = require("./drizzle-DiReZf6d.cjs");
3
+ const require_drizzle = require("./drizzle-bfjVzYR6.cjs");
4
4
  require("./internal-drizzle.cjs");
5
5
  //#region src/core-drizzle.ts
6
6
  require_deprecate_subpath.warnDeprecatedSubpath("clivly/core/drizzle", "clivly/internal/drizzle");
7
7
  //#endregion
8
+ exports.buildColumnsMeta = require_drizzle.buildColumnsMeta;
9
+ exports.buildUniqueConstraints = require_drizzle.buildUniqueConstraints;
8
10
  exports.discoverFromDrizzle = require_drizzle.discoverFromDrizzle;
@@ -1,2 +1,3 @@
1
- import { t as discoverFromDrizzle } from "./drizzle-DmeKSqeF.cjs";
2
- export { discoverFromDrizzle };
1
+ import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-BhN5M9zt.cjs";
2
+ import "./internal-drizzle.cjs";
3
+ export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };
@@ -1,2 +1,3 @@
1
- import { t as discoverFromDrizzle } from "./drizzle-CFOr9dU9.mjs";
2
- export { discoverFromDrizzle };
1
+ import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-kBULBAOa.mjs";
2
+ import "./internal-drizzle.mjs";
3
+ export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };
package/core-drizzle.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
2
- import { t as discoverFromDrizzle } from "./drizzle-B89tLo4T.mjs";
2
+ import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-3kvhkwO7.mjs";
3
3
  import "./internal-drizzle.mjs";
4
4
  //#region src/core-drizzle.ts
5
5
  warnDeprecatedSubpath("clivly/core/drizzle", "clivly/internal/drizzle");
6
6
  //#endregion
7
- export { discoverFromDrizzle };
7
+ export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_entity_config = require("./entity-config-D87rV-tE.cjs");
2
+ const require_entity_config = require("./entity-config-CsLl-ftC.cjs");
3
3
  //#region src/core-entity-config.ts
4
4
  require("./deprecate-subpath-B9ngvizt.cjs").warnDeprecatedSubpath("clivly/core/entity-config", "clivly/internal/entity-config");
5
5
  //#endregion
@@ -1,2 +1,2 @@
1
- import { C as validateEntitiesConfig, S as relationshipsSchema, _ as RelationshipsMap, a as ClivlyEntitiesConfig, b as filterSchema, c as ConfigValidationResult, d as FilterExpr, f as FilterValue, g as RelationshipVia, h as RelationshipSpec, i as ClivlyConfigError, l as CrmConcept, m as MaterializingConcept, n as CRM_CONCEPTS, o as ClivlyEntityConfig, p as MATERIALIZING_CONCEPTS, r as CUSTOM_CONCEPT, s as ConfigValidationError, t as CANONICAL_FIELDS, u as DiscoveredSchemaTable, v as defineClivlyConfig, x as relationshipSchema, y as entitiesConfigSchema } from "./entity-config-DoUCXtq5.cjs";
2
- export { CANONICAL_FIELDS, CRM_CONCEPTS, CUSTOM_CONCEPT, ClivlyConfigError, ClivlyEntitiesConfig, ClivlyEntityConfig, ConfigValidationError, ConfigValidationResult, CrmConcept, DiscoveredSchemaTable, FilterExpr, FilterValue, MATERIALIZING_CONCEPTS, MaterializingConcept, RelationshipSpec, RelationshipVia, RelationshipsMap, defineClivlyConfig, entitiesConfigSchema, filterSchema, relationshipSchema, relationshipsSchema, validateEntitiesConfig };
1
+ import { C as relationshipsSchema, S as relationshipSchema, _ as RelationshipVia, a as ClivlyEntitiesConfig, b as entitiesConfigSchema, c as ConfigValidationResult, d as DiscoveredSchemaTable, f as FilterExpr, g as RelationshipSpec, h as MaterializingConcept, i as ClivlyConfigError, l as CrmConcept, m as MATERIALIZING_CONCEPTS, n as CRM_CONCEPTS, o as ClivlyEntityConfig, p as FilterValue, r as CUSTOM_CONCEPT, s as ConfigValidationError, t as CANONICAL_FIELDS, u as DiscoveredColumnMeta, v as RelationshipsMap, w as validateEntitiesConfig, x as filterSchema, y as defineClivlyConfig } from "./entity-config-C4Yf_fPj.cjs";
2
+ export { CANONICAL_FIELDS, CRM_CONCEPTS, CUSTOM_CONCEPT, ClivlyConfigError, ClivlyEntitiesConfig, ClivlyEntityConfig, ConfigValidationError, ConfigValidationResult, CrmConcept, DiscoveredColumnMeta, DiscoveredSchemaTable, FilterExpr, FilterValue, MATERIALIZING_CONCEPTS, MaterializingConcept, RelationshipSpec, RelationshipVia, RelationshipsMap, defineClivlyConfig, entitiesConfigSchema, filterSchema, relationshipSchema, relationshipsSchema, validateEntitiesConfig };
@@ -1,2 +1,2 @@
1
- import { C as validateEntitiesConfig, S as relationshipsSchema, _ as RelationshipsMap, a as ClivlyEntitiesConfig, b as filterSchema, c as ConfigValidationResult, d as FilterExpr, f as FilterValue, g as RelationshipVia, h as RelationshipSpec, i as ClivlyConfigError, l as CrmConcept, m as MaterializingConcept, n as CRM_CONCEPTS, o as ClivlyEntityConfig, p as MATERIALIZING_CONCEPTS, r as CUSTOM_CONCEPT, s as ConfigValidationError, t as CANONICAL_FIELDS, u as DiscoveredSchemaTable, v as defineClivlyConfig, x as relationshipSchema, y as entitiesConfigSchema } from "./entity-config-DoUCXtq5.mjs";
2
- export { CANONICAL_FIELDS, CRM_CONCEPTS, CUSTOM_CONCEPT, ClivlyConfigError, ClivlyEntitiesConfig, ClivlyEntityConfig, ConfigValidationError, ConfigValidationResult, CrmConcept, DiscoveredSchemaTable, FilterExpr, FilterValue, MATERIALIZING_CONCEPTS, MaterializingConcept, RelationshipSpec, RelationshipVia, RelationshipsMap, defineClivlyConfig, entitiesConfigSchema, filterSchema, relationshipSchema, relationshipsSchema, validateEntitiesConfig };
1
+ import { C as relationshipsSchema, S as relationshipSchema, _ as RelationshipVia, a as ClivlyEntitiesConfig, b as entitiesConfigSchema, c as ConfigValidationResult, d as DiscoveredSchemaTable, f as FilterExpr, g as RelationshipSpec, h as MaterializingConcept, i as ClivlyConfigError, l as CrmConcept, m as MATERIALIZING_CONCEPTS, n as CRM_CONCEPTS, o as ClivlyEntityConfig, p as FilterValue, r as CUSTOM_CONCEPT, s as ConfigValidationError, t as CANONICAL_FIELDS, u as DiscoveredColumnMeta, v as RelationshipsMap, w as validateEntitiesConfig, x as filterSchema, y as defineClivlyConfig } from "./entity-config-C4Yf_fPj.mjs";
2
+ export { CANONICAL_FIELDS, CRM_CONCEPTS, CUSTOM_CONCEPT, ClivlyConfigError, ClivlyEntitiesConfig, ClivlyEntityConfig, ConfigValidationError, ConfigValidationResult, CrmConcept, DiscoveredColumnMeta, DiscoveredSchemaTable, FilterExpr, FilterValue, MATERIALIZING_CONCEPTS, MaterializingConcept, RelationshipSpec, RelationshipVia, RelationshipsMap, defineClivlyConfig, entitiesConfigSchema, filterSchema, relationshipSchema, relationshipsSchema, validateEntitiesConfig };
@@ -1,4 +1,4 @@
1
- import { a as MATERIALIZING_CONCEPTS, c as filterSchema, d as validateEntitiesConfig, i as ClivlyConfigError, l as relationshipSchema, n as CRM_CONCEPTS, o as defineClivlyConfig, r as CUSTOM_CONCEPT, s as entitiesConfigSchema, t as CANONICAL_FIELDS, u as relationshipsSchema } from "./entity-config-va2bkH5o.mjs";
1
+ import { a as MATERIALIZING_CONCEPTS, c as filterSchema, d as validateEntitiesConfig, i as ClivlyConfigError, l as relationshipSchema, n as CRM_CONCEPTS, o as defineClivlyConfig, r as CUSTOM_CONCEPT, s as entitiesConfigSchema, t as CANONICAL_FIELDS, u as relationshipsSchema } from "./entity-config-D3LmzgLb.mjs";
2
2
  import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
3
3
  //#region src/core-entity-config.ts
4
4
  warnDeprecatedSubpath("clivly/core/entity-config", "clivly/internal/entity-config");