Skip to content

Commit 2b907a1

Browse files
committed
feat: improve cli dx
1 parent b67bb98 commit 2b907a1

File tree

22 files changed

+786
-891
lines changed

22 files changed

+786
-891
lines changed

.changeset/eager-cougars-watch.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@cipherstash/basic-example": minor
3+
"@cipherstash/stack": minor
4+
---
5+
6+
Improve CLI user experience for developer onboarding.
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { encryptedTable, encryptedColumn } from '@cipherstash/stack/schema'
22
import { Encryption } from '@cipherstash/stack'
33

4-
export const helloTable = encryptedTable('hello', {
5-
world: encryptedColumn('world').equality().orderAndRange(),
6-
name: encryptedColumn('name').equality().freeTextSearch(),
7-
age: encryptedColumn('age').dataType('number').equality().orderAndRange(),
4+
export const usersTable = encryptedTable('users', {
5+
email: encryptedColumn('email')
6+
.equality()
7+
.orderAndRange()
8+
.freeTextSearch(),
89
})
910

1011
export const encryptionClient = await Encryption({
11-
schemas: [helloTable],
12+
schemas: [usersTable],
1213
})

packages/stack-forge/README.md

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,27 @@ bun add -D @cipherstash/stack-forge
3030

3131
## Quick Start
3232

33-
The fastest way to get started is with the interactive `init` command:
33+
First, initialize your project with the `stash` CLI (from `@cipherstash/stack`):
3434

3535
```bash
36-
npx stash-forge init
36+
npx stash init
3737
```
3838

39-
This will:
40-
1. Check if `@cipherstash/stack` is installed and offer to install it
41-
2. Ask for your database URL
42-
3. Ask which integration you're using (Drizzle, Supabase, or plain PostgreSQL)
43-
4. Let you build an encryption schema interactively or use a placeholder
44-
5. Generate `stash.config.ts` and your encryption client file
39+
This generates your encryption schema and installs `@cipherstash/stack-forge` as a dev dependency.
4540

46-
Then install EQL in your database:
41+
Then set up your database and install EQL:
4742

4843
```bash
49-
npx stash-forge install
44+
npx stash-forge setup
5045
```
5146

47+
This will:
48+
1. Auto-detect your encryption client file (or ask for the path)
49+
2. Ask for your database URL
50+
3. Generate `stash.config.ts`
51+
4. Ask which Postgres provider you're using (Supabase, Neon, AWS RDS, etc.) to determine the right install flags
52+
5. Install EQL extensions in your database
53+
5254
That's it. EQL is now installed and your encryption schema is ready.
5355

5456
### Manual setup
@@ -64,6 +66,7 @@ import { defineConfig } from '@cipherstash/stack-forge'
6466

6567
export default defineConfig({
6668
databaseUrl: process.env.DATABASE_URL!,
69+
client: './src/encryption/index.ts',
6770
})
6871
```
6972

@@ -117,25 +120,34 @@ The config file is resolved by walking up from the current working directory, si
117120
stash-forge <command> [options]
118121
```
119122

120-
### `init`
123+
### `setup`
121124

122-
Initialize CipherStash Forge in your project with an interactive wizard.
125+
Configure your database and install EQL extensions. Run this after `stash init` has set up your encryption schema.
123126

124127
```bash
125-
npx stash-forge init
128+
npx stash-forge setup [options]
126129
```
127130

128131
The wizard will:
129-
- Check if `@cipherstash/stack` is installed and prompt to install it (detects your package manager automatically)
132+
- Auto-detect your encryption client file by scanning common locations (`./src/encryption/index.ts`, etc.), then confirm with you or ask for the path if not found
130133
- Ask for your database URL (pre-fills from `DATABASE_URL` env var)
131-
- Ask which integration you're using (Drizzle ORM, Supabase, or plain PostgreSQL)
132-
- Ask where to create the encryption client file
133-
- If the client file already exists, ask whether to keep it or overwrite
134-
- Let you choose between building a schema interactively or using a placeholder:
135-
- **Build a schema:** asks for table name, column names, data types, and search operations for each column
136-
- **Placeholder:** generates an example `users` table with `email` and `name` columns
137-
- Generate `stash.config.ts` and the encryption client file
138-
- Print next steps with links to the [CipherStash dashboard](https://dashboard.cipherstash.com/sign-in) for credentials
134+
- Generate `stash.config.ts` with the database URL and client path
135+
- Ask which Postgres provider you're using to determine the right install flags:
136+
- **Supabase** — uses `--supabase` (no operator families + Supabase role grants)
137+
- **Neon, Vercel Postgres, PlanetScale, Prisma Postgres** — uses `--exclude-operator-family`
138+
- **AWS RDS, Other / Self-hosted** — standard install
139+
- Install EQL extensions in your database
140+
141+
If `--supabase` is passed as a flag, the provider selection is skipped.
142+
143+
| Option | Description |
144+
|--------|-------------|
145+
| `--force` | Overwrite existing `stash.config.ts` and reinstall EQL |
146+
| `--dry-run` | Show what would happen without making changes |
147+
| `--supabase` | Skip provider selection and use Supabase-compatible install |
148+
| `--drizzle` | Generate a Drizzle migration instead of direct install |
149+
| `--exclude-operator-family` | Skip operator family creation |
150+
| `--latest` | Fetch the latest EQL from GitHub instead of using the bundled version |
139151

140152
### `install`
141153

packages/stack-forge/src/bin/stash-forge.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ config()
33

44
import * as p from '@clack/prompts'
55
import {
6-
initCommand,
76
installCommand,
87
pushCommand,
8+
setupCommand,
99
statusCommand,
1010
testConnectionCommand,
1111
upgradeCommand,
@@ -19,7 +19,7 @@ Usage: stash-forge <command> [options]
1919
Commands:
2020
install Install EQL extensions into your database
2121
upgrade Upgrade EQL extensions to the latest version
22-
init Initialize CipherStash Forge in your project
22+
setup Configure database and install EQL extensions
2323
push Push encryption schema to database (CipherStash Proxy only)
2424
validate Validate encryption schema for common misconfigurations
2525
migrate Run pending encrypt config migrations
@@ -29,12 +29,12 @@ Commands:
2929
Options:
3030
--help, -h Show help
3131
--version, -v Show version
32-
--force (install) Reinstall even if already installed
33-
--dry-run (install, push, upgrade) Show what would happen without making changes
34-
--supabase (install, upgrade, validate) Use Supabase-compatible install and grant role permissions
35-
--drizzle (install) Generate a Drizzle migration instead of direct install
36-
--exclude-operator-family (install, upgrade, validate) Skip operator family creation (for non-superuser roles)
37-
--latest (install, upgrade) Fetch the latest EQL from GitHub instead of using the bundled version
32+
--force (setup, install) Reinstall even if already installed
33+
--dry-run (setup, install, push, upgrade) Show what would happen without making changes
34+
--supabase (setup, install, upgrade, validate) Use Supabase-compatible install and grant role permissions
35+
--drizzle (setup, install) Generate a Drizzle migration instead of direct install
36+
--exclude-operator-family (setup, install, upgrade, validate) Skip operator family creation (for non-superuser roles)
37+
--latest (setup, install, upgrade) Fetch the latest EQL from GitHub instead of using the bundled version
3838
`.trim()
3939

4040
interface ParsedArgs {
@@ -115,8 +115,17 @@ async function main() {
115115
case 'status':
116116
await statusCommand()
117117
break
118-
case 'init':
119-
await initCommand()
118+
case 'setup':
119+
await setupCommand({
120+
force: flags.force,
121+
dryRun: flags['dry-run'],
122+
supabase: flags.supabase,
123+
excludeOperatorFamily: flags['exclude-operator-family'],
124+
drizzle: flags.drizzle,
125+
latest: flags.latest,
126+
name: values.name,
127+
out: values.out,
128+
})
120129
break
121130
case 'test-connection':
122131
await testConnectionCommand()

packages/stack-forge/src/commands/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { initCommand } from './init.js'
1+
export { setupCommand } from './init.js'
22
export { installCommand } from './install.js'
33
export { pushCommand } from './push.js'
44
export { statusCommand } from './status.js'

0 commit comments

Comments
 (0)