-
Notifications
You must be signed in to change notification settings - Fork 3
feat: consolidate cli tools into @cipherstash/cli #336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,22 @@ | ||
| import { encryptedTable, encryptedColumn } from '@cipherstash/stack/schema' | ||
| import { pgTable, integer, timestamp } from 'drizzle-orm/pg-core' | ||
| import { encryptedType, extractEncryptionSchema } from '@cipherstash/stack/drizzle' | ||
| import { Encryption } from '@cipherstash/stack' | ||
|
|
||
| export const usersTable = encryptedTable('users', { | ||
| email: encryptedColumn('email') | ||
| .equality() | ||
| .orderAndRange() | ||
| .freeTextSearch(), | ||
| export const usersTable = pgTable('users', { | ||
| id: integer('id').primaryKey().generatedAlwaysAsIdentity(), | ||
| email: encryptedType<string>('email', { | ||
| equality: true, | ||
| freeTextSearch: true, | ||
| }), | ||
| name: encryptedType<string>('name', { | ||
| equality: true, | ||
| freeTextSearch: true, | ||
| }), | ||
| createdAt: timestamp('created_at').defaultNow(), | ||
| }) | ||
|
|
||
| const usersSchema = extractEncryptionSchema(usersTable) | ||
|
|
||
| export const encryptionClient = await Encryption({ | ||
| schemas: [usersTable], | ||
| schemas: [usersSchema], | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { encryptedSupabase } from '@cipherstash/stack/supabase' | ||
| import { encryptionClient, contactsTable } from '../../encryption/index' | ||
| import { createServerClient } from './server' | ||
|
|
||
| const supabase = await createServerClient() | ||
| export const eSupabase = encryptedSupabase({ | ||
| encryptionClient, | ||
| supabaseClient: supabase, | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { createClient } from '@supabase/supabase-js' | ||
|
|
||
| export async function createServerClient() { | ||
| const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL! | ||
| const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! | ||
|
|
||
| return createClient(supabaseUrl, supabaseKey) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import { eSupabase } from '../lib/supabase/encrypted' | ||
| import { contactsTable } from '../encryption/index' | ||
|
|
||
| // Example queries using encrypted Supabase wrapper | ||
|
|
||
| export async function getAllContacts() { | ||
| const { data, error } = await eSupabase | ||
| .from('contacts', contactsTable) | ||
| .select('id, name, email, role') // explicit columns, no * | ||
| .order('created_at', { ascending: false }) | ||
|
|
||
| return { data, error } | ||
| } | ||
|
|
||
| export async function getContactsByRole(role: string) { | ||
| const { data, error } = await eSupabase | ||
| .from('contacts', contactsTable) | ||
| .select('id, name, email, role') | ||
| .eq('role', role) // auto-encrypted | ||
|
|
||
| return { data, error } | ||
| } | ||
|
|
||
| export async function searchContactsByName(searchTerm: string) { | ||
| const { data, error } = await eSupabase | ||
| .from('contacts', contactsTable) | ||
| .select('id, name, email, role') | ||
| .ilike('name', `%${searchTerm}%`) // auto-encrypted | ||
|
|
||
| return { data, error } | ||
| } | ||
|
|
||
| export async function createContact(contact: { name: string; email: string; role: string }) { | ||
| const { data, error } = await eSupabase | ||
| .from('contacts', contactsTable) | ||
| .insert(contact) // auto-encrypted | ||
| .select('id, name, email, role') | ||
| .single() | ||
|
|
||
| return { data, error } | ||
| } | ||
|
|
||
| export async function updateContact(id: string, updates: Partial<{ name: string; email: string; role: string }>) { | ||
| const { data, error } = await eSupabase | ||
| .from('contacts', contactsTable) | ||
| .update(updates) // auto-encrypted | ||
| .eq('id', id) | ||
| .select('id, name, email, role') | ||
| .single() | ||
|
|
||
| return { data, error } | ||
| } | ||
|
|
||
| export async function deleteContact(id: string) { | ||
| const { error } = await eSupabase | ||
| .from('contacts', contactsTable) | ||
| .delete() | ||
| .eq('id', id) | ||
|
|
||
| return { error } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,10 +18,26 @@ | |
| "url": "git+https://github.com/cipherstash/protectjs.git" | ||
| }, | ||
| "license": "MIT", | ||
| "workspaces": [ | ||
| "examples/*", | ||
| "packages/*" | ||
| ], | ||
| "workspaces": { | ||
| "packages": [ | ||
| "packages/*", | ||
| "examples/*" | ||
| ], | ||
| "catalogs": { | ||
| "repo": { | ||
| "@cipherstash/auth": "0.35.0", | ||
| "tsup": "8.4.0", | ||
| "tsx": "4.19.3", | ||
| "typescript": "5.6.3", | ||
| "vitest": "3.1.3" | ||
| }, | ||
| "security": { | ||
| "@clerk/nextjs": "6.31.2", | ||
| "next": "15.5.10", | ||
| "vite": "6.4.1" | ||
| } | ||
| } | ||
| }, | ||
| "scripts": { | ||
| "build": "turbo build --filter './packages/*'", | ||
| "build:js": "turbo build --filter './packages/protect' --filter './packages/nextjs'", | ||
|
|
@@ -46,29 +62,6 @@ | |
| "node": ">=22" | ||
| }, | ||
| "pnpm": { | ||
| "overrides": { | ||
| "@cipherstash/protect-ffi": "0.21.0", | ||
| "@babel/runtime": "7.26.10", | ||
| "brace-expansion@^5": ">=5.0.5", | ||
| "body-parser": "2.2.1", | ||
| "vite": "catalog:security", | ||
| "pg": "^8.16.3", | ||
| "postgres": "^3.4.7", | ||
| "js-yaml": "3.14.2", | ||
| "test-exclude": "^7.0.1", | ||
| "glob": ">=11.1.0", | ||
| "qs": ">=6.14.1", | ||
| "lodash": ">=4.17.23", | ||
| "minimatch": ">=10.2.3", | ||
| "@isaacs/brace-expansion": ">=5.0.1", | ||
| "fast-xml-parser": ">=5.3.4", | ||
| "next": ">=15.5.10", | ||
| "ajv": ">=8.18.0", | ||
| "esbuild@<=0.24.2": ">=0.25.0", | ||
| "picomatch@^4": ">=4.0.4", | ||
| "picomatch@^2": ">=2.3.2", | ||
| "rollup@>=4.0.0 <4.59.0": ">=4.59.0" | ||
| }, | ||
| "peerDependencyRules": { | ||
| "ignoreMissing": [ | ||
| "@types/pg", | ||
|
|
@@ -80,5 +73,27 @@ | |
| } | ||
| }, | ||
| "dedupe-peer-dependents": true | ||
| }, | ||
| "overrides": { | ||
| "@babel/runtime": "7.26.10", | ||
| "brace-expansion@^5": ">=5.0.5", | ||
| "body-parser": "2.2.1", | ||
| "vite": "catalog:security", | ||
| "pg": "^8.16.3", | ||
| "postgres": "^3.4.7", | ||
| "js-yaml": "3.14.2", | ||
| "test-exclude": "^7.0.1", | ||
| "glob": ">=11.1.0", | ||
| "qs": ">=6.14.1", | ||
| "lodash": ">=4.17.23", | ||
| "minimatch": ">=10.2.3", | ||
| "@isaacs/brace-expansion": ">=5.0.1", | ||
| "fast-xml-parser": ">=5.3.4", | ||
| "next": ">=15.5.10", | ||
| "ajv": ">=8.18.0", | ||
| "esbuild@<=0.24.2": ">=0.25.0", | ||
| "picomatch@^4": ">=4.0.4", | ||
| "picomatch@^2": ">=2.3.2", | ||
| "rollup@>=4.0.0 <4.59.0": ">=4.59.0" | ||
| } | ||
|
Comment on lines
+77
to
98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Yes. pnpm supports root-level dependency overrides via the Example: {
"pnpm": {
"overrides": {
"foo": "^1.0.0",
"bar@^2.1.0": "3.0.0",
"qar@1>zoo": "2"
}
}
}
``` ([dimava.github.io](https://dimava.github.io/pnpm/package_json/))
Citations:
- 1: https://dimava.github.io/pnpm/package_json/
- 2: https://dimava.github.io/pnpm/package_json/
---
🏁 Script executed:
```shell
find . -name "package.json" -type f | head -5Repository: cipherstash/stack Length of output: 196 🏁 Script executed: cat -n ./package.json | head -100Repository: cipherstash/stack Length of output: 3262 Move The Suggested fix "pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@types/pg",
"pg",
"postgres"
],
"allowedVersions": {
"drizzle-orm": "*"
}
},
"dedupe-peer-dependents": true,
"overrides": {
"@babel/runtime": "7.26.10",
"brace-expansion@^5": ">=5.0.5",
...
}
}The Node.js version requirement (>= 22) is correctly specified in the engines field. 🤖 Prompt for AI Agents |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: cipherstash/stack
Length of output: 391
🌐 Web query:
Does pnpm support catalogs in package.json workspaces field?💡 Result:
No. pnpm catalogs are not read from
package.json#workspaces.In pnpm, catalogs are defined in
pnpm-workspace.yaml(viacatalog:/catalogs:) and then referenced from individual packages’package.jsonfiles using thecatalog:protocol in dependency specifiers. (pnpm.cn)If you’ve seen catalogs under
package.json#workspaces, that’s a Bun workspace feature/documentation pattern, not pnpm’s. (fossies.org)Related: pnpm has historically required
pnpm-workspace.yamlrather than usingpackage.json#workspaces(there’s even a discussion proposing the opposite, which implies it’s not how pnpm works today). (github.com)Citations:
Remove the
workspaces.catalogsobject from package.json—it's dead code in a pnpm project.The
workspacesfield withcatalogsis a Bun workspace feature. pnpm does not read or usepackage.json#workspaces.catalogs. Instead, pnpm exclusively reads workspace and catalog configuration frompnpm-workspace.yaml. The catalog definitions inpackage.json(lines 30–40) duplicate those inpnpm-workspace.yamland will never be used, creating maintenance burden and potential for version drift between the two files.Since this project uses pnpm, move any needed catalog reference to
pnpm-workspace.yamlonly and remove the entireworkspacesobject frompackage.json.🤖 Prompt for AI Agents