@cipherstash/stack 0.18.0 → 1.0.0-rc.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 (111) hide show
  1. package/CHANGELOG.md +704 -0
  2. package/README.md +97 -79
  3. package/dist/adapter-kit.cjs +923 -0
  4. package/dist/adapter-kit.cjs.map +1 -0
  5. package/dist/adapter-kit.d.cts +82 -0
  6. package/dist/adapter-kit.d.ts +82 -0
  7. package/dist/adapter-kit.js +47 -0
  8. package/dist/adapter-kit.js.map +1 -0
  9. package/dist/base-operation-AOAIvsSB.d.cts +32 -0
  10. package/dist/base-operation-FXEzUXIq.d.ts +32 -0
  11. package/dist/{chunk-VPOTNP4K.js → chunk-3B5ZX3IS.js} +3 -1
  12. package/dist/chunk-3B5ZX3IS.js.map +1 -0
  13. package/dist/chunk-7333ZC6L.js +48 -0
  14. package/dist/chunk-7333ZC6L.js.map +1 -0
  15. package/dist/{chunk-XWPGAHBZ.js → chunk-BNO32ZMV.js} +1 -1
  16. package/dist/chunk-BNO32ZMV.js.map +1 -0
  17. package/dist/chunk-CLM7E4I6.js +4439 -0
  18. package/dist/chunk-CLM7E4I6.js.map +1 -0
  19. package/dist/{chunk-LLCCNKDL.js → chunk-HQANMV7R.js} +3 -3
  20. package/dist/{chunk-LLCCNKDL.js.map → chunk-HQANMV7R.js.map} +1 -1
  21. package/dist/chunk-JSG2AMDI.js +17 -0
  22. package/dist/chunk-JSG2AMDI.js.map +1 -0
  23. package/dist/chunk-OFQ555AX.js +191 -0
  24. package/dist/chunk-OFQ555AX.js.map +1 -0
  25. package/dist/chunk-PZ5AY32C.js +10 -0
  26. package/dist/chunk-PZ5AY32C.js.map +1 -0
  27. package/dist/chunk-V2Q3NYIH.js +494 -0
  28. package/dist/chunk-V2Q3NYIH.js.map +1 -0
  29. package/dist/chunk-X3JRXEIB.js +98 -0
  30. package/dist/chunk-X3JRXEIB.js.map +1 -0
  31. package/dist/{chunk-ZYOZHZMJ.js → chunk-ZTP5QJ27.js} +193 -169
  32. package/dist/chunk-ZTP5QJ27.js.map +1 -0
  33. package/dist/client.cjs +4124 -49
  34. package/dist/client.cjs.map +1 -1
  35. package/dist/client.d.cts +6 -5
  36. package/dist/client.d.ts +6 -5
  37. package/dist/client.js +3 -1
  38. package/dist/columns-D2_YzrCX.d.cts +622 -0
  39. package/dist/columns-rZc7fQHI.d.ts +622 -0
  40. package/dist/dynamodb/index.cjs +19 -12
  41. package/dist/dynamodb/index.cjs.map +1 -1
  42. package/dist/dynamodb/index.d.cts +3 -2
  43. package/dist/dynamodb/index.d.ts +3 -2
  44. package/dist/dynamodb/index.js +8 -10
  45. package/dist/dynamodb/index.js.map +1 -1
  46. package/dist/encryption/index.cjs +4496 -222
  47. package/dist/encryption/index.cjs.map +1 -1
  48. package/dist/encryption/index.d.cts +807 -6
  49. package/dist/encryption/index.d.ts +807 -6
  50. package/dist/encryption/index.js +15 -7
  51. package/dist/encryption/v3.cjs +7896 -0
  52. package/dist/encryption/v3.cjs.map +1 -0
  53. package/dist/encryption/v3.d.cts +103 -0
  54. package/dist/encryption/v3.d.ts +103 -0
  55. package/dist/encryption/v3.js +189 -0
  56. package/dist/encryption/v3.js.map +1 -0
  57. package/dist/eql/v3/index.cjs +663 -0
  58. package/dist/eql/v3/index.cjs.map +1 -0
  59. package/dist/eql/v3/index.d.cts +173 -0
  60. package/dist/eql/v3/index.d.ts +173 -0
  61. package/dist/eql/v3/index.js +99 -0
  62. package/dist/eql/v3/index.js.map +1 -0
  63. package/dist/errors/index.js +1 -0
  64. package/dist/identity/index.cjs +55 -35
  65. package/dist/identity/index.cjs.map +1 -1
  66. package/dist/identity/index.d.cts +54 -30
  67. package/dist/identity/index.d.ts +54 -30
  68. package/dist/identity/index.js +9 -177
  69. package/dist/identity/index.js.map +1 -1
  70. package/dist/index-BquA71_Y.d.ts +24 -0
  71. package/dist/index-fhWTOV0K.d.cts +24 -0
  72. package/dist/index.cjs +4547 -243
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.d.cts +18 -19
  75. package/dist/index.d.ts +18 -19
  76. package/dist/index.js +20 -5
  77. package/dist/index.js.map +1 -1
  78. package/dist/schema/index.cjs +4128 -49
  79. package/dist/schema/index.cjs.map +1 -1
  80. package/dist/schema/index.d.cts +1 -1
  81. package/dist/schema/index.d.ts +1 -1
  82. package/dist/schema/index.js +3 -1
  83. package/dist/{types-public-BTxqjmtv.d.cts → types-public-QMjYNfQO.d.cts} +448 -251
  84. package/dist/{types-public-BTxqjmtv.d.ts → types-public-QMjYNfQO.d.ts} +448 -251
  85. package/dist/types-public.cjs.map +1 -1
  86. package/dist/types-public.d.cts +2 -2
  87. package/dist/types-public.d.ts +2 -2
  88. package/dist/types-public.js +2 -1
  89. package/dist/wasm-inline.d.ts +1643 -0
  90. package/dist/wasm-inline.js +4901 -0
  91. package/dist/wasm-inline.js.map +1 -0
  92. package/package.json +74 -52
  93. package/dist/chunk-VPOTNP4K.js.map +0 -1
  94. package/dist/chunk-XWPGAHBZ.js.map +0 -1
  95. package/dist/chunk-YWQXTZ5M.js +0 -383
  96. package/dist/chunk-YWQXTZ5M.js.map +0 -1
  97. package/dist/chunk-ZYOZHZMJ.js.map +0 -1
  98. package/dist/client-CIsfZ2zg.d.ts +0 -692
  99. package/dist/client-Dt98Rugc.d.cts +0 -692
  100. package/dist/drizzle/index.cjs +0 -1558
  101. package/dist/drizzle/index.cjs.map +0 -1
  102. package/dist/drizzle/index.d.cts +0 -358
  103. package/dist/drizzle/index.d.ts +0 -358
  104. package/dist/drizzle/index.js +0 -1215
  105. package/dist/drizzle/index.js.map +0 -1
  106. package/dist/supabase/index.cjs +0 -1526
  107. package/dist/supabase/index.cjs.map +0 -1
  108. package/dist/supabase/index.d.cts +0 -144
  109. package/dist/supabase/index.d.ts +0 -144
  110. package/dist/supabase/index.js +0 -899
  111. package/dist/supabase/index.js.map +0 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The all-in-one TypeScript SDK for the CipherStash data security stack.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@cipherstash/stack.svg?style=for-the-badge&labelColor=000000)](https://www.npmjs.com/package/@cipherstash/stack)
6
- [![License: MIT](https://img.shields.io/npm/l/@cipherstash/stack.svg?style=for-the-badge&labelColor=000000)](https://github.com/cipherstash/protectjs/blob/main/LICENSE.md)
6
+ [![License: MIT](https://img.shields.io/npm/l/@cipherstash/stack.svg?style=for-the-badge&labelColor=000000)](https://github.com/cipherstash/stack/blob/main/LICENSE.md)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-first-blue?style=for-the-badge&labelColor=000000)](https://www.typescriptlang.org/)
8
8
 
9
9
  --
@@ -17,7 +17,6 @@ The all-in-one TypeScript SDK for the CipherStash data security stack.
17
17
  - [Encryption and Decryption](#encryption-and-decryption)
18
18
  - [Searchable Encryption](#searchable-encryption)
19
19
  - [Identity-Aware Encryption](#identity-aware-encryption)
20
- - [Secrets Management](#secrets-management)
21
20
  - [CLI Reference](#cli-reference)
22
21
  - [Configuration](#configuration)
23
22
  - [Error Handling](#error-handling)
@@ -94,8 +93,7 @@ if (decrypted.failure) {
94
93
  - **Searchable encryption** - Exact match, free-text search, order/range queries, and encrypted JSONB queries in PostgreSQL.
95
94
  - **Bulk operations** - Encrypt or decrypt thousands of values in a single ZeroKMS call (`bulkEncrypt`, `bulkDecrypt`, `bulkEncryptModels`, `bulkDecryptModels`).
96
95
  - **Identity-aware encryption** - Tie encryption to a user's JWT via `LockContext`, so only that user can decrypt.
97
- - **Secrets management** - Store, retrieve, list, and delete encrypted secrets with the `Secrets` class.
98
- - **CLI (`stash`)** - Initialize projects, manage secrets, and set up encryption from the terminal.
96
+ - **CLI (`stash`)** - Initialize projects and set up encryption from the terminal.
99
97
  - **TypeScript-first** - Strongly typed schemas, results, and model operations with full generics support.
100
98
 
101
99
  ## Schema Definition
@@ -309,11 +307,11 @@ Operator family support for Supabase is being developed in collaboration with th
309
307
 
310
308
  Encrypted data is stored as an [EQL](https://github.com/cipherstash/encrypt-query-language) JSON payload. Install the EQL extension in PostgreSQL to enable searchable queries, then store encrypted data in `eql_v2_encrypted` columns.
311
309
 
312
- The `@cipherstash/stack/drizzle` module provides `encryptedType` for defining encrypted columns and `createEncryptionOperators` for querying them:
310
+ The `@cipherstash/stack-drizzle` module provides `encryptedType` for defining encrypted columns and `createEncryptionOperators` for querying them:
313
311
 
314
312
  ```typescript
315
313
  import { pgTable, integer, timestamp } from "drizzle-orm/pg-core"
316
- import { encryptedType, extractEncryptionSchema, createEncryptionOperators } from "@cipherstash/stack/drizzle"
314
+ import { encryptedType, extractEncryptionSchema, createEncryptionOperators } from "@cipherstash/stack-drizzle"
317
315
  import { Encryption } from "@cipherstash/stack"
318
316
 
319
317
  // Define schema with encrypted columns
@@ -366,6 +364,87 @@ For columns with `searchableJson: true`, three JSONB operators are available:
366
364
 
367
365
  These operators encrypt the JSON path selector using the `steVecSelector` query type and cast it to `eql_v2_encrypted` for use with the EQL PostgreSQL functions.
368
366
 
367
+ ### EQL v3 Concrete-Type Columns (Drizzle)
368
+
369
+ The `@cipherstash/stack-drizzle/v3` module targets EQL v3, where each encrypted column is a **concrete Postgres domain type** (`eql_v3.text_eq`, `eql_v3.integer_ord`, …). Instead of toggling capability flags, you pick a concrete type from the `types` namespace and its query capabilities are fixed by that choice. It is the `/v3` subpath of the same `@cipherstash/stack-drizzle` package whose v2 surface is shown above.
370
+
371
+ Declare a Drizzle table using the `types` factories. The suffix encodes the capability: `*Eq` (equality), `*Ord` (order + range, which also covers equality), `*Match` / `TextSearch` (free-text search), and the bare name (e.g. `Text`, `Bigint`) is storage-only.
372
+
373
+ ```ts
374
+ import { pgTable, integer } from "drizzle-orm/pg-core"
375
+ import { drizzle } from "drizzle-orm/postgres-js"
376
+ import {
377
+ types,
378
+ createEncryptionOperatorsV3,
379
+ extractEncryptionSchemaV3,
380
+ } from "@cipherstash/stack-drizzle/v3"
381
+ import { EncryptionV3 } from "@cipherstash/stack/v3"
382
+
383
+ // Capabilities come from the concrete type — no flags to configure.
384
+ const users = pgTable("users", {
385
+ id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
386
+ email: types.TextEq("email"), // equality: eq / ne / inArray
387
+ age: types.IntegerOrd("age"), // order + range: gt/gte/lt/lte, between, asc/desc
388
+ bio: types.TextMatch("bio"), // free-text search: contains
389
+ balance: types.Bigint("balance"), // storage only (no query capability)
390
+ })
391
+ ```
392
+
393
+ Derive the v3 schema from the table, build the typed client, and create the capability-checked operators:
394
+
395
+ ```ts
396
+ const usersSchema = extractEncryptionSchemaV3(users)
397
+ const client = await EncryptionV3({ schemas: [usersSchema] })
398
+ const ops = createEncryptionOperatorsV3(client)
399
+
400
+ const db = drizzle({ client: sqlClient })
401
+ ```
402
+
403
+ The operators auto-encrypt their operands and validate them against the column's concrete type. Applying an operator the type doesn't support throws `EncryptionOperatorError`:
404
+
405
+ ```ts
406
+ // Equality — email is TextEq
407
+ const exact = await db.select().from(users)
408
+ .where(await ops.eq(users.email, "alice@example.com"))
409
+
410
+ // Range + ordering — age is IntegerOrd
411
+ const adults = await db.select().from(users)
412
+ .where(await ops.gte(users.age, 18))
413
+ .orderBy(ops.asc(users.age))
414
+
415
+ const midBand = await db.select().from(users)
416
+ .where(await ops.between(users.age, 25, 40))
417
+
418
+ // Set membership — built on equality
419
+ const listed = await db.select().from(users)
420
+ .where(await ops.inArray(users.email, ["alice@example.com", "bob@example.com"]))
421
+
422
+ // Free-text token containment — bio is TextMatch
423
+ const coffee = await db.select().from(users)
424
+ .where(await ops.contains(users.bio, "coffee"))
425
+ ```
426
+
427
+ Rows are **pre-encrypted** with `client.bulkEncryptModels(...)` before they reach `db.insert(...).values(...)` — Drizzle never sees plaintext. `Bigint` columns take a native JS `bigint`:
428
+
429
+ ```ts
430
+ const rows = await client.bulkEncryptModels(
431
+ [
432
+ { email: "alice@example.com", age: 30, bio: "climbing and coffee", balance: 100_000n },
433
+ { email: "bob@example.com", age: 41, bio: "cycling and coffee", balance: 250_000n },
434
+ ],
435
+ usersSchema,
436
+ )
437
+ if (rows.failure) throw new Error(rows.failure.message)
438
+
439
+ await db.insert(users).values(rows.data)
440
+ ```
441
+
442
+ Notes:
443
+
444
+ - **Free-text search uses `ops.contains`** (token containment on a `match` index), not SQL `like` / `ilike`. It matches whole indexed tokens, so `contains(users.bio, "coffee")` finds rows whose `bio` contains the token `coffee`.
445
+ - **The concrete type defines the legal operators.** `TextEq` supports `eq` / `ne` / `inArray` / `notInArray`; `*Ord` types add `gt` / `gte` / `lt` / `lte` / `between` / `notBetween` and `asc` / `desc`; `*Match` and `TextSearch` add `contains`; a bare `Text` / `Integer` / `Bigint` column is storage-only. Using an unsupported operator throws `EncryptionOperatorError`.
446
+ - Combine conditions with `ops.and` / `ops.or`, and do NULL checks with `ops.isNull` / `ops.isNotNull` (the where-clause operators are `async` and must be `await`ed; `ops.asc` / `ops.desc` are synchronous).
447
+
369
448
  ## Identity-Aware Encryption
370
449
 
371
450
  Lock encryption to a specific user by requiring a valid JWT for decryption.
@@ -398,44 +477,6 @@ const decrypted = await client
398
477
 
399
478
  Lock contexts work with all operations: `encrypt`, `decrypt`, `encryptModel`, `decryptModel`, `bulkEncryptModels`, `bulkDecryptModels`, `bulkEncrypt`, `bulkDecrypt`.
400
479
 
401
- ## Secrets Management
402
-
403
- The `Secrets` class provides end-to-end encrypted secret storage. Values are encrypted locally before being sent to the CipherStash API.
404
-
405
- ```typescript
406
- import { Secrets } from "@cipherstash/stack/secrets"
407
-
408
- const secrets = new Secrets({
409
- workspaceCRN: process.env.CS_WORKSPACE_CRN!,
410
- clientId: process.env.CS_CLIENT_ID!,
411
- clientKey: process.env.CS_CLIENT_KEY!,
412
- apiKey: process.env.CS_CLIENT_ACCESS_KEY!,
413
- environment: "production",
414
- })
415
-
416
- // Store a secret
417
- await secrets.set("DATABASE_URL", "postgres://user:pass@host:5432/db")
418
-
419
- // Retrieve and decrypt a single secret
420
- const result = await secrets.get("DATABASE_URL")
421
- if (!result.failure) {
422
- console.log(result.data) // "postgres://user:pass@host:5432/db"
423
- }
424
-
425
- // Retrieve multiple secrets in one call
426
- const many = await secrets.getMany(["DATABASE_URL", "API_KEY"])
427
- if (!many.failure) {
428
- console.log(many.data.DATABASE_URL)
429
- console.log(many.data.API_KEY)
430
- }
431
-
432
- // List secret names (values stay encrypted)
433
- const list = await secrets.list()
434
-
435
- // Delete a secret
436
- await secrets.delete("DATABASE_URL")
437
- ```
438
-
439
480
  ## CLI Reference
440
481
 
441
482
  The CLI is available via `npx stash` after install.
@@ -472,24 +513,6 @@ After init, run `npx stash db setup` to configure your database.
472
513
  |------|-------------|
473
514
  | `--supabase` | Use Supabase-specific setup flow |
474
515
 
475
- ### `npx stash secrets`
476
-
477
- Manage encrypted secrets from the terminal.
478
-
479
- ```bash
480
- npx stash secrets set -name DATABASE_URL -value "postgres://..." -environment production
481
- npx stash secrets get -name DATABASE_URL -environment production
482
- npx stash secrets list -environment production
483
- npx stash secrets delete -name DATABASE_URL -environment production
484
- ```
485
-
486
- | Command | Flags | Aliases | Description |
487
- |-----|----|-----|-------|
488
- | `npx stash secrets set` | `-name`, `-value`, `-environment` | `-n`, `-V`, `-e` | Encrypt and store a secret |
489
- | `npx stash secrets get` | `-name`, `-environment` | `-n`, `-e` | Retrieve and decrypt a secret |
490
- | `npx stash secrets list` | `-environment` | `-e` | List all secret names in an environment |
491
- | `npx stash secrets delete` | `-name`, `-environment`, `-yes` | `-n`, `-e`, `-y` | Delete a secret (prompts for confirmation unless `-yes`) |
492
-
493
516
  ## Configuration
494
517
 
495
518
  ### Local Development
@@ -552,7 +575,7 @@ const client2 = await Encryption({
552
575
 
553
576
  ### Logging
554
577
 
555
- The SDK uses structured logging across all interfaces (Encryption, Secrets, Supabase, DynamoDB). Each operation emits a single wide event with context such as the operation type, table, column, lock context status, and duration.
578
+ The SDK uses structured logging across all interfaces (Encryption, Supabase, DynamoDB). Each operation emits a single wide event with context such as the operation type, table, column, lock context status, and duration.
556
579
 
557
580
  Configure the log level with the `STASH_STACK_LOG` environment variable:
558
581
 
@@ -631,19 +654,6 @@ const lc = new LockContext(options?)
631
654
  const result = await lc.identify(jwtToken)
632
655
  ```
633
656
 
634
- ### `Secrets`
635
-
636
- ```typescript
637
- import { Secrets } from "@cipherstash/stack/secrets"
638
-
639
- const secrets = new Secrets(config)
640
- await secrets.set(name, value)
641
- await secrets.get(name)
642
- await secrets.getMany(names)
643
- await secrets.list()
644
- await secrets.delete(name)
645
- ```
646
-
647
657
  ### Schema Builders
648
658
 
649
659
  ```typescript
@@ -661,9 +671,18 @@ csValue(valueName) // returns ProtectValue (for nested values)
661
671
  | `@cipherstash/stack` | `Encryption` function (main entry point) |
662
672
  | `@cipherstash/stack/schema` | `encryptedTable`, `encryptedColumn`, `csValue`, schema types |
663
673
  | `@cipherstash/stack/identity` | `LockContext` class and identity types |
664
- | `@cipherstash/stack/secrets` | `Secrets` class and secrets types |
665
674
  | `@cipherstash/stack/client` | Client-safe exports (schema builders and types only - no native FFI) |
666
675
  | `@cipherstash/stack/types` | All TypeScript types (`Encrypted`, `Decrypted`, `ClientConfig`, `EncryptionClientConfig`, query types, etc.) |
676
+ | `@cipherstash/stack/v3` | `EncryptionV3` typed client plus the EQL v3 authoring DSL (`encryptedTable`, `types`, v3 type helpers) |
677
+
678
+ The Drizzle and Supabase integrations are **separate first-party packages** that
679
+ depend on `@cipherstash/stack` (they are no longer subpaths of it):
680
+
681
+ | Package | Provides |
682
+ |-------|-----|
683
+ | `@cipherstash/stack-drizzle` | Drizzle ORM integration (EQL v2): `encryptedType`, `extractEncryptionSchema`, `createEncryptionOperators` |
684
+ | `@cipherstash/stack-drizzle/v3` | EQL v3 Drizzle integration: `types` column factories, `createEncryptionOperatorsV3`, `extractEncryptionSchemaV3`, `makeEqlV3Column`, `EncryptionOperatorError` |
685
+ | `@cipherstash/stack-supabase` | Supabase integration: `encryptedSupabase` (v2) and `encryptedSupabaseV3` (v3) |
667
686
 
668
687
  ## Migration from @cipherstash/protect
669
688
 
@@ -675,7 +694,6 @@ If you are migrating from `@cipherstash/protect`, the following table maps the o
675
694
  | `csTable(name, cols)` | `encryptedTable(name, cols)` | `@cipherstash/stack/schema` |
676
695
  | `csColumn(name)` | `encryptedColumn(name)` | `@cipherstash/stack/schema` |
677
696
  | `import { LockContext } from "@cipherstash/protect/identify"` | `import { LockContext } from "@cipherstash/stack/identity"` | `@cipherstash/stack/identity` |
678
- | N/A | `Secrets` class | `@cipherstash/stack/secrets` |
679
697
  | N/A | CLI | `npx stash` |
680
698
 
681
699
  All method signatures on the encryption client (`encrypt`, `decrypt`, `encryptModel`, etc.) remain the same. The `Result` pattern (`data` / `failure`) is unchanged.
@@ -687,4 +705,4 @@ All method signatures on the encryption client (`encrypt`, `decrypt`, `encryptMo
687
705
 
688
706
  ## License
689
707
 
690
- MIT - see [LICENSE.md](https://github.com/cipherstash/protectjs/blob/main/LICENSE.md).
708
+ MIT - see [LICENSE.md](https://github.com/cipherstash/stack/blob/main/LICENSE.md).