@cipherstash/stack 0.2.0 → 0.4.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 (67) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +2 -3
  3. package/dist/bin/stash.js +109 -186
  4. package/dist/bin/stash.js.map +1 -1
  5. package/dist/{chunk-SUYMGQBY.js → chunk-4RNBI3UH.js} +1 -7
  6. package/dist/chunk-4RNBI3UH.js.map +1 -0
  7. package/dist/{chunk-5G4F4JJG.js → chunk-KOU2MHXJ.js} +1 -1
  8. package/dist/chunk-KOU2MHXJ.js.map +1 -0
  9. package/dist/{chunk-5DCT6YU2.js → chunk-OAPLZLR5.js} +7 -3
  10. package/dist/{chunk-5DCT6YU2.js.map → chunk-OAPLZLR5.js.map} +1 -1
  11. package/dist/{chunk-LHZ6KZIG.js → chunk-WUZGKTMG.js} +84 -162
  12. package/dist/chunk-WUZGKTMG.js.map +1 -0
  13. package/dist/{chunk-7XRPN2KX.js → chunk-Y35W4WFN.js} +31 -28
  14. package/dist/chunk-Y35W4WFN.js.map +1 -0
  15. package/dist/{client-D-ZH8SB2.d.cts → client-CUGXheRq.d.cts} +33 -31
  16. package/dist/{client-BV9pXC-d.d.ts → client-CrGQnSlk.d.ts} +33 -31
  17. package/dist/client.cjs +30 -27
  18. package/dist/client.cjs.map +1 -1
  19. package/dist/client.d.cts +2 -2
  20. package/dist/client.d.ts +2 -2
  21. package/dist/client.js +5 -5
  22. package/dist/drizzle/index.cjs +24 -21
  23. package/dist/drizzle/index.cjs.map +1 -1
  24. package/dist/drizzle/index.d.cts +5 -5
  25. package/dist/drizzle/index.d.ts +5 -5
  26. package/dist/drizzle/index.js +2 -2
  27. package/dist/drizzle/index.js.map +1 -1
  28. package/dist/dynamodb/index.cjs.map +1 -1
  29. package/dist/dynamodb/index.d.cts +10 -10
  30. package/dist/dynamodb/index.d.ts +10 -10
  31. package/dist/dynamodb/index.js.map +1 -1
  32. package/dist/identity/index.cjs +6 -2
  33. package/dist/identity/index.cjs.map +1 -1
  34. package/dist/identity/index.js +1 -1
  35. package/dist/index.cjs +113 -190
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +3 -3
  38. package/dist/index.d.ts +3 -3
  39. package/dist/index.js +8 -8
  40. package/dist/schema/index.cjs +36 -33
  41. package/dist/schema/index.cjs.map +1 -1
  42. package/dist/schema/index.d.cts +1 -1
  43. package/dist/schema/index.d.ts +1 -1
  44. package/dist/schema/index.js +11 -11
  45. package/dist/secrets/index.cjs +109 -186
  46. package/dist/secrets/index.cjs.map +1 -1
  47. package/dist/secrets/index.d.cts +1 -1
  48. package/dist/secrets/index.d.ts +1 -1
  49. package/dist/secrets/index.js +5 -5
  50. package/dist/secrets/index.js.map +1 -1
  51. package/dist/supabase/index.cjs +9 -9
  52. package/dist/supabase/index.cjs.map +1 -1
  53. package/dist/supabase/index.d.cts +3 -3
  54. package/dist/supabase/index.d.ts +3 -3
  55. package/dist/supabase/index.js +4 -4
  56. package/dist/supabase/index.js.map +1 -1
  57. package/dist/{types-public-Dfg-hkuQ.d.cts → types-public-Wj6tB_ux.d.cts} +115 -76
  58. package/dist/{types-public-Dfg-hkuQ.d.ts → types-public-Wj6tB_ux.d.ts} +115 -76
  59. package/dist/types-public.cjs.map +1 -1
  60. package/dist/types-public.d.cts +1 -1
  61. package/dist/types-public.d.ts +1 -1
  62. package/dist/types-public.js +1 -1
  63. package/package.json +2 -2
  64. package/dist/chunk-5G4F4JJG.js.map +0 -1
  65. package/dist/chunk-7XRPN2KX.js.map +0 -1
  66. package/dist/chunk-LHZ6KZIG.js.map +0 -1
  67. package/dist/chunk-SUYMGQBY.js.map +0 -1
@@ -16,10 +16,9 @@ type Brand<T, B extends string> = T & {
16
16
  };
17
17
  type Client = Awaited<ReturnType<typeof newClient>> | undefined;
18
18
  /** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */
19
- type EncryptedValue = Brand<Encrypted$1, 'encrypted'> | null;
19
+ type EncryptedValue = Brand<Encrypted$1, 'encrypted'>;
20
20
  /** Structural type representing encrypted data. See also `EncryptedValue` for branded nominal typing. */
21
- type Encrypted = Encrypted$1 | null;
22
- type EncryptPayload = JsPlaintext | null;
21
+ type Encrypted = Encrypted$1;
23
22
  type KeysetIdentifier = {
24
23
  name: string;
25
24
  } | {
@@ -61,34 +60,40 @@ type ClientConfig = {
61
60
  };
62
61
  type AtLeastOneCsTable<T> = [T, ...T[]];
63
62
  type EncryptionClientConfig = {
64
- schemas: AtLeastOneCsTable<ProtectTable<ProtectTableColumn>>;
63
+ schemas: AtLeastOneCsTable<EncryptedTable<EncryptedTableColumn>>;
65
64
  config?: ClientConfig;
66
65
  logging?: LoggingConfig;
67
66
  };
67
+ /**
68
+ * Options for single-value encrypt operations.
69
+ * Use a column from your table schema (from {@link encryptedColumn}) or a nested
70
+ * field (from {@link encryptedField}) as the target for encryption.
71
+ */
68
72
  type EncryptOptions = {
69
- column: ProtectColumn | ProtectValue;
70
- table: ProtectTable<ProtectTableColumn>;
73
+ /** The column or nested field to encrypt into. From {@link EncryptedColumn} or {@link EncryptedField}. */
74
+ column: EncryptedColumn | EncryptedField;
75
+ table: EncryptedTable<EncryptedTableColumn>;
71
76
  };
72
77
  /** Format for encrypted query/search term return values */
73
78
  type EncryptedReturnType = 'eql' | 'composite-literal' | 'escaped-composite-literal';
74
79
  type SearchTerm = {
75
80
  value: JsPlaintext;
76
- column: ProtectColumn;
77
- table: ProtectTable<ProtectTableColumn>;
81
+ column: EncryptedColumn;
82
+ table: EncryptedTable<EncryptedTableColumn>;
78
83
  returnType?: EncryptedReturnType;
79
84
  };
80
85
  /** Encrypted search term result: EQL object or composite literal string */
81
86
  type EncryptedSearchTerm = Encrypted | string;
82
- /** Result of encryptQuery (single or batch): EQL, composite literal string, or null */
83
- type EncryptedQueryResult = Encrypted | string | null;
87
+ /** Result of encryptQuery (single or batch): EQL or composite literal string */
88
+ type EncryptedQueryResult = Encrypted | string;
84
89
  type EncryptedFields<T> = {
85
- [K in keyof T as T[K] extends Encrypted ? K : never]: T[K];
90
+ [K in keyof T as NonNullable<T[K]> extends Encrypted ? K : never]: T[K];
86
91
  };
87
92
  type OtherFields<T> = {
88
- [K in keyof T as T[K] extends Encrypted ? never : K]: T[K];
93
+ [K in keyof T as NonNullable<T[K]> extends Encrypted ? never : K]: T[K];
89
94
  };
90
95
  type DecryptedFields<T> = {
91
- [K in keyof T as T[K] extends Encrypted ? K : never]: string;
96
+ [K in keyof T as NonNullable<T[K]> extends Encrypted ? K : never]: null extends T[K] ? string | null : string;
92
97
  };
93
98
  /** Model with encrypted fields replaced by plaintext (decrypted) values */
94
99
  type Decrypted<T> = OtherFields<T> & DecryptedFields<T>;
@@ -98,7 +103,7 @@ type Decrypted<T> = OtherFields<T> & DecryptedFields<T>;
98
103
  * Fields whose keys match columns defined in `S` become `Encrypted`;
99
104
  * all other fields retain their original types from `T`.
100
105
  *
101
- * When `S` is the widened `ProtectTableColumn` (e.g. when a user passes an
106
+ * When `S` is the widened `EncryptedTableColumn` (e.g. when a user passes an
102
107
  * explicit `<User>` type argument without specifying `S`), the type degrades
103
108
  * gracefully to `T` — preserving backward compatibility.
104
109
  *
@@ -109,16 +114,16 @@ type Decrypted<T> = OtherFields<T> & DecryptedFields<T>;
109
114
  * ```typescript
110
115
  * type User = { id: string; email: string }
111
116
  * // With a schema that defines `email`:
112
- * type Encrypted = EncryptedFromSchema<User, { email: ProtectColumn }>
117
+ * type Encrypted = EncryptedFromSchema<User, { email: EncryptedColumn }>
113
118
  * // => { id: string; email: Encrypted }
114
119
  * ```
115
120
  */
116
- type EncryptedFromSchema<T, S extends ProtectTableColumn> = {
117
- [K in keyof T]: [K] extends [keyof S] ? [S[K & keyof S]] extends [ProtectColumn | ProtectValue] ? Encrypted : T[K] : T[K];
121
+ type EncryptedFromSchema<T, S extends EncryptedTableColumn> = {
122
+ [K in keyof T]: [K] extends [keyof S] ? [S[K & keyof S]] extends [EncryptedColumn | EncryptedField] ? null extends T[K] ? Encrypted | null : Encrypted : T[K] : T[K];
118
123
  };
119
124
  type BulkEncryptPayload = Array<{
120
125
  id?: string;
121
- plaintext: JsPlaintext | null;
126
+ plaintext: JsPlaintext;
122
127
  }>;
123
128
  type BulkEncryptedData = Array<{
124
129
  id?: string;
@@ -128,7 +133,7 @@ type BulkDecryptPayload = Array<{
128
133
  id?: string;
129
134
  data: Encrypted;
130
135
  }>;
131
- type BulkDecryptedData = Array<DecryptionResult<JsPlaintext | null>>;
136
+ type BulkDecryptedData = Array<DecryptionResult<JsPlaintext>>;
132
137
  type DecryptionSuccess<T> = {
133
138
  error?: never;
134
139
  data: T;
@@ -166,14 +171,14 @@ declare const queryTypes: {
166
171
  };
167
172
  /** @internal */
168
173
  type QueryTermBase = {
169
- column: ProtectColumn;
170
- table: ProtectTable<ProtectTableColumn>;
174
+ column: EncryptedColumn;
175
+ table: EncryptedTable<EncryptedTableColumn>;
171
176
  queryType?: QueryTypeName;
172
177
  returnType?: EncryptedReturnType;
173
178
  };
174
179
  type EncryptQueryOptions = QueryTermBase;
175
180
  type ScalarQueryTerm = QueryTermBase & {
176
- value: JsPlaintext | null;
181
+ value: JsPlaintext;
177
182
  };
178
183
 
179
184
  /**
@@ -186,6 +191,7 @@ type ScalarQueryTerm = QueryTermBase & {
186
191
  * - `"number"`
187
192
  * - `"string"`
188
193
  * - `"json"`
194
+ * - `"text"`
189
195
  *
190
196
  * @remarks
191
197
  * This is a Zod enum used at runtime to validate schema definitions.
@@ -193,7 +199,7 @@ type ScalarQueryTerm = QueryTermBase & {
193
199
  *
194
200
  * @internal
195
201
  */
196
- declare const castAsEnum: z.ZodDefault<z.ZodEnum<["bigint", "boolean", "date", "number", "string", "json"]>>;
202
+ declare const castAsEnum: z.ZodDefault<z.ZodEnum<["bigint", "boolean", "date", "number", "string", "json", "text"]>>;
197
203
  declare const tokenFilterSchema: z.ZodObject<{
198
204
  kind: z.ZodLiteral<"downcase">;
199
205
  }, "strip", z.ZodTypeAny, {
@@ -281,7 +287,7 @@ declare const steVecIndexOptsSchema: z.ZodObject<{
281
287
  prefix: string;
282
288
  }>;
283
289
  declare const columnSchema: z.ZodDefault<z.ZodObject<{
284
- cast_as: z.ZodDefault<z.ZodEnum<["bigint", "boolean", "date", "number", "string", "json"]>>;
290
+ cast_as: z.ZodDefault<z.ZodEnum<["bigint", "boolean", "date", "number", "string", "json", "text"]>>;
285
291
  indexes: z.ZodDefault<z.ZodObject<{
286
292
  ore: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
287
293
  unique: z.ZodOptional<z.ZodObject<{
@@ -412,7 +418,7 @@ declare const columnSchema: z.ZodDefault<z.ZodObject<{
412
418
  } | undefined;
413
419
  }>>;
414
420
  }, "strip", z.ZodTypeAny, {
415
- cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json";
421
+ cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json" | "text";
416
422
  indexes: {
417
423
  match?: {
418
424
  token_filters?: {
@@ -439,7 +445,7 @@ declare const columnSchema: z.ZodDefault<z.ZodObject<{
439
445
  } | undefined;
440
446
  };
441
447
  }, {
442
- cast_as?: "string" | "number" | "bigint" | "boolean" | "date" | "json" | undefined;
448
+ cast_as?: "string" | "number" | "bigint" | "boolean" | "date" | "json" | "text" | undefined;
443
449
  indexes?: {
444
450
  match?: {
445
451
  token_filters?: {
@@ -470,7 +476,7 @@ declare const columnSchema: z.ZodDefault<z.ZodObject<{
470
476
  declare const encryptConfigSchema: z.ZodObject<{
471
477
  v: z.ZodNumber;
472
478
  tables: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodDefault<z.ZodObject<{
473
- cast_as: z.ZodDefault<z.ZodEnum<["bigint", "boolean", "date", "number", "string", "json"]>>;
479
+ cast_as: z.ZodDefault<z.ZodEnum<["bigint", "boolean", "date", "number", "string", "json", "text"]>>;
474
480
  indexes: z.ZodDefault<z.ZodObject<{
475
481
  ore: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
476
482
  unique: z.ZodOptional<z.ZodObject<{
@@ -601,7 +607,7 @@ declare const encryptConfigSchema: z.ZodObject<{
601
607
  } | undefined;
602
608
  }>>;
603
609
  }, "strip", z.ZodTypeAny, {
604
- cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json";
610
+ cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json" | "text";
605
611
  indexes: {
606
612
  match?: {
607
613
  token_filters?: {
@@ -628,7 +634,7 @@ declare const encryptConfigSchema: z.ZodObject<{
628
634
  } | undefined;
629
635
  };
630
636
  }, {
631
- cast_as?: "string" | "number" | "bigint" | "boolean" | "date" | "json" | undefined;
637
+ cast_as?: "string" | "number" | "bigint" | "boolean" | "date" | "json" | "text" | undefined;
632
638
  indexes?: {
633
639
  match?: {
634
640
  token_filters?: {
@@ -658,7 +664,7 @@ declare const encryptConfigSchema: z.ZodObject<{
658
664
  }, "strip", z.ZodTypeAny, {
659
665
  v: number;
660
666
  tables: Record<string, Record<string, {
661
- cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json";
667
+ cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json" | "text";
662
668
  indexes: {
663
669
  match?: {
664
670
  token_filters?: {
@@ -688,7 +694,7 @@ declare const encryptConfigSchema: z.ZodObject<{
688
694
  }, {
689
695
  v: number;
690
696
  tables?: Record<string, Record<string, {
691
- cast_as?: "string" | "number" | "bigint" | "boolean" | "date" | "json" | undefined;
697
+ cast_as?: "string" | "number" | "bigint" | "boolean" | "date" | "json" | "text" | undefined;
692
698
  indexes?: {
693
699
  match?: {
694
700
  token_filters?: {
@@ -729,45 +735,54 @@ type SteVecIndexOpts = z.infer<typeof steVecIndexOptsSchema>;
729
735
  type UniqueIndexOpts = z.infer<typeof uniqueIndexOptsSchema>;
730
736
  type OreIndexOpts = z.infer<typeof oreIndexOptsSchema>;
731
737
  type ColumnSchema = z.infer<typeof columnSchema>;
732
- type ProtectTableColumn = {
733
- [key: string]: ProtectColumn | {
734
- [key: string]: ProtectValue | {
735
- [key: string]: ProtectValue | {
736
- [key: string]: ProtectValue;
738
+ /**
739
+ * Shape of table columns: either top-level {@link EncryptedColumn} or nested
740
+ * objects whose leaves are {@link EncryptedField}. Used with {@link encryptedTable}.
741
+ */
742
+ type EncryptedTableColumn = {
743
+ [key: string]: EncryptedColumn | {
744
+ [key: string]: EncryptedField | {
745
+ [key: string]: EncryptedField | {
746
+ [key: string]: EncryptedField;
737
747
  };
738
748
  };
739
749
  };
740
750
  };
741
751
  type EncryptConfig = z.infer<typeof encryptConfigSchema>;
742
- declare class ProtectValue {
752
+ /**
753
+ * Builder for a nested encrypted field (encrypted but not searchable).
754
+ * Create with {@link encryptedField}. Use inside nested objects in {@link encryptedTable};
755
+ * supports `.dataType()` for plaintext type. No index methods (equality, orderAndRange, etc.).
756
+ */
757
+ declare class EncryptedField {
743
758
  private valueName;
744
759
  private castAsValue;
745
760
  constructor(valueName: string);
746
761
  /**
747
- * Set or override the plaintext data type for this value.
762
+ * Set or override the plaintext data type for this field.
748
763
  *
749
764
  * By default all values are treated as `'string'`. Use this method to specify
750
765
  * a different type so the encryption layer knows how to encode the plaintext
751
766
  * before encrypting.
752
767
  *
753
- * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
754
- * @returns This `ProtectValue` instance for method chaining.
768
+ * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.
769
+ * @returns This `EncryptedField` instance for method chaining.
755
770
  *
756
771
  * @example
757
772
  * ```typescript
758
- * import { encryptedValue } from "@cipherstash/stack/schema"
773
+ * import { encryptedField } from "@cipherstash/stack/schema"
759
774
  *
760
- * const age = encryptedValue("age").dataType("number")
775
+ * const age = encryptedField("age").dataType("number")
761
776
  * ```
762
777
  */
763
778
  dataType(castAs: CastAs): this;
764
779
  build(): {
765
- cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json";
780
+ cast_as: "number" | "bigint" | "boolean" | "date" | "json" | "text";
766
781
  indexes: {};
767
782
  };
768
783
  getName(): string;
769
784
  }
770
- declare class ProtectColumn {
785
+ declare class EncryptedColumn {
771
786
  private columnName;
772
787
  private castAsValue;
773
788
  private indexesValue;
@@ -780,7 +795,7 @@ declare class ProtectColumn {
780
795
  * before encrypting.
781
796
  *
782
797
  * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
783
- * @returns This `ProtectColumn` instance for method chaining.
798
+ * @returns This `EncryptedColumn` instance for method chaining.
784
799
  *
785
800
  * @example
786
801
  * ```typescript
@@ -796,7 +811,7 @@ declare class ProtectColumn {
796
811
  * ORE allows sorting, comparison, and range queries on encrypted data.
797
812
  * Use with `encryptQuery` and `queryType: 'orderAndRange'`.
798
813
  *
799
- * @returns This `ProtectColumn` instance for method chaining.
814
+ * @returns This `EncryptedColumn` instance for method chaining.
800
815
  *
801
816
  * @example
802
817
  * ```typescript
@@ -816,7 +831,7 @@ declare class ProtectColumn {
816
831
  *
817
832
  * @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).
818
833
  * When omitted, no token filters are applied.
819
- * @returns This `ProtectColumn` instance for method chaining.
834
+ * @returns This `EncryptedColumn` instance for method chaining.
820
835
  *
821
836
  * @example
822
837
  * ```typescript
@@ -836,7 +851,7 @@ declare class ProtectColumn {
836
851
  *
837
852
  * @param opts - Optional match index configuration. Defaults to 3-character ngram
838
853
  * tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.
839
- * @returns This `ProtectColumn` instance for method chaining.
854
+ * @returns This `EncryptedColumn` instance for method chaining.
840
855
  *
841
856
  * @example
842
857
  * ```typescript
@@ -868,7 +883,7 @@ declare class ProtectColumn {
868
883
  * the plaintext type: strings become selector queries, objects/arrays become
869
884
  * containment queries.
870
885
  *
871
- * @returns This `ProtectColumn` instance for method chaining.
886
+ * @returns This `EncryptedColumn` instance for method chaining.
872
887
  *
873
888
  * @example
874
889
  * ```typescript
@@ -881,7 +896,7 @@ declare class ProtectColumn {
881
896
  */
882
897
  searchableJson(): this;
883
898
  build(): {
884
- cast_as: "string" | "number" | "bigint" | "boolean" | "date" | "json";
899
+ cast_as: "number" | "bigint" | "boolean" | "date" | "json" | "text";
885
900
  indexes: {
886
901
  ore?: OreIndexOpts;
887
902
  unique?: UniqueIndexOpts;
@@ -895,9 +910,11 @@ interface TableDefinition {
895
910
  tableName: string;
896
911
  columns: Record<string, ColumnSchema>;
897
912
  }
898
- declare class ProtectTable<T extends ProtectTableColumn> {
913
+ declare class EncryptedTable<T extends EncryptedTableColumn> {
899
914
  readonly tableName: string;
900
915
  private readonly columnBuilders;
916
+ /** @internal Type-level brand so TypeScript can infer `T` from `EncryptedTable<T>`. */
917
+ readonly _columnType: T;
901
918
  constructor(tableName: string, columnBuilders: T);
902
919
  /**
903
920
  * Compile this table schema into a `TableDefinition` used internally by the encryption client.
@@ -921,7 +938,7 @@ declare class ProtectTable<T extends ProtectTableColumn> {
921
938
  build(): TableDefinition;
922
939
  }
923
940
  /**
924
- * Infer the plaintext (decrypted) type from a ProtectTable schema.
941
+ * Infer the plaintext (decrypted) type from a EncryptedTable schema.
925
942
  *
926
943
  * @example
927
944
  * ```typescript
@@ -934,11 +951,11 @@ declare class ProtectTable<T extends ProtectTableColumn> {
934
951
  * // => { email: string; name: string }
935
952
  * ```
936
953
  */
937
- type InferPlaintext<T extends ProtectTable<any>> = T extends ProtectTable<infer C> ? {
938
- [K in keyof C as C[K] extends ProtectColumn | ProtectValue ? K : never]: string;
954
+ type InferPlaintext<T extends EncryptedTable<any>> = T extends EncryptedTable<infer C> ? {
955
+ [K in keyof C as C[K] extends EncryptedColumn | EncryptedField ? K : never]: string;
939
956
  } : never;
940
957
  /**
941
- * Infer the encrypted type from a ProtectTable schema.
958
+ * Infer the encrypted type from a EncryptedTable schema.
942
959
  *
943
960
  * @example
944
961
  * ```typescript
@@ -950,13 +967,13 @@ type InferPlaintext<T extends ProtectTable<any>> = T extends ProtectTable<infer
950
967
  * // => { email: Encrypted }
951
968
  * ```
952
969
  */
953
- type InferEncrypted<T extends ProtectTable<any>> = T extends ProtectTable<infer C> ? {
954
- [K in keyof C as C[K] extends ProtectColumn | ProtectValue ? K : never]: Encrypted;
970
+ type InferEncrypted<T extends EncryptedTable<any>> = T extends EncryptedTable<infer C> ? {
971
+ [K in keyof C as C[K] extends EncryptedColumn | EncryptedField ? K : never]: Encrypted;
955
972
  } : never;
956
973
  /**
957
974
  * Define an encrypted table schema.
958
975
  *
959
- * Creates a `ProtectTable` that maps a database table name to a set of encrypted
976
+ * Creates a `EncryptedTable` that maps a database table name to a set of encrypted
960
977
  * column definitions. Pass the resulting object to `Encryption({ schemas: [...] })`
961
978
  * when initializing the client.
962
979
  *
@@ -966,8 +983,9 @@ type InferEncrypted<T extends ProtectTable<any>> = T extends ProtectTable<infer
966
983
  *
967
984
  * @param tableName - The name of the database table this schema represents.
968
985
  * @param columns - An object whose keys are logical column names and values are
969
- * `ProtectColumn` instances created with {@link encryptedColumn}.
970
- * @returns A `ProtectTable<T> & T` that can be used as both a schema definition
986
+ * {@link EncryptedColumn} from {@link encryptedColumn}, or nested objects whose
987
+ * leaves are {@link EncryptedField} from {@link encryptedField}.
988
+ * @returns A `EncryptedTable<T> & T` that can be used as both a schema definition
971
989
  * and a column accessor.
972
990
  *
973
991
  * @example
@@ -986,17 +1004,17 @@ type InferEncrypted<T extends ProtectTable<any>> = T extends ProtectTable<infer
986
1004
  * await client.encrypt("hello@example.com", { column: users.email, table: users })
987
1005
  * ```
988
1006
  */
989
- declare function encryptedTable<T extends ProtectTableColumn>(tableName: string, columns: T): ProtectTable<T> & T;
1007
+ declare function encryptedTable<T extends EncryptedTableColumn>(tableName: string, columns: T): EncryptedTable<T> & T;
990
1008
  /**
991
1009
  * Define an encrypted column within a table schema.
992
1010
  *
993
- * Creates a `ProtectColumn` builder for the given column name. Chain index
1011
+ * Creates a `EncryptedColumn` builder for the given column name. Chain index
994
1012
  * methods (`.equality()`, `.freeTextSearch()`, `.orderAndRange()`,
995
1013
  * `.searchableJson()`) and/or `.dataType()` to configure searchable encryption
996
1014
  * and the plaintext data type.
997
1015
  *
998
1016
  * @param columnName - The name of the database column to encrypt.
999
- * @returns A new `ProtectColumn` builder.
1017
+ * @returns A new `EncryptedColumn` builder.
1000
1018
  *
1001
1019
  * @example
1002
1020
  * ```typescript
@@ -1007,31 +1025,52 @@ declare function encryptedTable<T extends ProtectTableColumn>(tableName: string,
1007
1025
  * })
1008
1026
  * ```
1009
1027
  */
1010
- declare function encryptedColumn(columnName: string): ProtectColumn;
1028
+ declare function encryptedColumn(columnName: string): EncryptedColumn;
1011
1029
  /**
1012
- * Define an encrypted value for use in nested or structured schemas.
1030
+ * Define an encrypted field for use in nested or structured schemas.
1013
1031
  *
1014
- * `encryptedValue` is similar to {@link encryptedColumn} but creates a `ProtectValue`
1015
- * intended for nested fields within a table schema. It supports `.dataType()`
1016
- * for specifying the plaintext type.
1032
+ * `encryptedField` is similar to {@link encryptedColumn} but creates an {@link EncryptedField}
1033
+ * for nested fields that are encrypted but not searchable (no indexes). Use `.dataType()`
1034
+ * to specify the plaintext type.
1017
1035
  *
1018
1036
  * @param valueName - The name of the value field.
1019
- * @returns A new `ProtectValue` builder.
1037
+ * @returns A new `EncryptedField` builder.
1020
1038
  *
1021
1039
  * @example
1022
1040
  * ```typescript
1023
- * import { encryptedTable, encryptedValue } from "@cipherstash/stack/schema"
1041
+ * import { encryptedTable, encryptedField } from "@cipherstash/stack/schema"
1024
1042
  *
1025
1043
  * const orders = encryptedTable("orders", {
1026
1044
  * details: {
1027
- * amount: encryptedValue("amount").dataType("number"),
1028
- * currency: encryptedValue("currency"),
1045
+ * amount: encryptedField("amount").dataType("number"),
1046
+ * currency: encryptedField("currency"),
1029
1047
  * },
1030
1048
  * })
1031
1049
  * ```
1032
1050
  */
1033
- declare function encryptedValue(valueName: string): ProtectValue;
1034
- /** @internal */
1035
- declare function buildEncryptConfig(...protectTables: Array<ProtectTable<ProtectTableColumn>>): EncryptConfig;
1051
+ declare function encryptedField(valueName: string): EncryptedField;
1052
+ /**
1053
+ * Build an encrypt config from a list of encrypted tables.
1054
+ *
1055
+ * @param ...tables - The list of encrypted tables to build the config from.
1056
+ * @returns An encrypt config object.
1057
+ *
1058
+ * @example
1059
+ * ```typescript
1060
+ * import { buildEncryptConfig } from "@cipherstash/stack/schema"
1061
+ *
1062
+ * const users = encryptedTable("users", {
1063
+ * email: encryptedColumn("email").equality(),
1064
+ * })
1065
+ *
1066
+ * const orders = encryptedTable("orders", {
1067
+ * amount: encryptedColumn("amount").dataType("number"),
1068
+ * })
1069
+ *
1070
+ * const config = buildEncryptConfig(users, orders)
1071
+ * console.log(config)
1072
+ * ```
1073
+ */
1074
+ declare function buildEncryptConfig(...protectTables: Array<EncryptedTable<EncryptedTableColumn>>): EncryptConfig;
1036
1075
 
1037
- export { type SearchTerm as A, type BulkDecryptedData as B, type CastAs as C, type Decrypted as D, type EncryptionClientConfig as E, type EncryptedSearchTerm as F, type EncryptedFields as G, type OtherFields as H, type InferPlaintext as I, type DecryptedFields as J, type KeysetIdentifier as K, type DecryptionResult as L, type MatchIndexOpts as M, type LoggingConfig as N, type OreIndexOpts as O, ProtectColumn as P, type QueryTypeName as Q, queryTypes as R, type ScalarQueryTerm as S, type TokenFilter as T, type UniqueIndexOpts as U, encryptedColumn as a, encryptedValue as b, type InferEncrypted as c, ProtectTable as d, encryptedTable as e, type ProtectTableColumn as f, ProtectValue as g, type EncryptedFromSchema as h, type Encrypted as i, type EncryptedValue as j, type EncryptedQueryResult as k, type Client as l, type BulkDecryptPayload as m, type BulkEncryptedData as n, type BulkEncryptPayload as o, type EncryptOptions as p, type EncryptQueryOptions as q, type EncryptedReturnType as r, type EncryptConfig as s, castAsEnum as t, encryptConfigSchema as u, type SteVecIndexOpts as v, type ColumnSchema as w, buildEncryptConfig as x, type EncryptPayload as y, type ClientConfig as z };
1076
+ export { type SearchTerm as A, type BulkDecryptedData as B, type CastAs as C, type Decrypted as D, type EncryptionClientConfig as E, type EncryptedSearchTerm as F, type EncryptedFields as G, type OtherFields as H, type InferPlaintext as I, type DecryptedFields as J, type KeysetIdentifier as K, type DecryptionResult as L, type MatchIndexOpts as M, type LoggingConfig as N, type OreIndexOpts as O, queryTypes as P, type QueryTypeName as Q, type ScalarQueryTerm as S, type TokenFilter as T, type UniqueIndexOpts as U, encryptedColumn as a, encryptedField as b, type InferEncrypted as c, EncryptedColumn as d, encryptedTable as e, EncryptedTable as f, type EncryptedTableColumn as g, EncryptedField as h, type EncryptedFromSchema as i, type Encrypted as j, type EncryptedValue as k, type EncryptedQueryResult as l, type Client as m, type BulkDecryptPayload as n, type BulkEncryptedData as o, type BulkEncryptPayload as p, type EncryptOptions as q, type EncryptQueryOptions as r, type EncryptedReturnType as s, type EncryptConfig as t, castAsEnum as u, encryptConfigSchema as v, type SteVecIndexOpts as w, type ColumnSchema as x, buildEncryptConfig as y, type ClientConfig as z };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types-public.ts","../src/types.ts"],"sourcesContent":["/**\n * Public type re-exports for `@cipherstash/stack/types`.\n *\n * This module exposes only the public types from the internal types module.\n * Internal helpers (`queryTypeToFfi`, `queryTypeToQueryOp`, `FfiIndexTypeName`,\n * `QueryTermBase`) are excluded.\n */\n\n// Core types\nexport type {\n Client,\n EncryptedValue,\n Encrypted,\n EncryptPayload,\n} from '@/types'\n\n// Client configuration\nexport type {\n KeysetIdentifier,\n ClientConfig,\n EncryptionClientConfig,\n} from '@/types'\n\n// Encrypt / decrypt operation options and results\nexport type {\n EncryptOptions,\n EncryptedReturnType,\n SearchTerm,\n EncryptedSearchTerm,\n EncryptedQueryResult,\n} from '@/types'\n\n// Model field types\nexport type {\n EncryptedFields,\n OtherFields,\n DecryptedFields,\n Decrypted,\n} from '@/types'\n\n// Bulk operations\nexport type {\n BulkEncryptPayload,\n BulkEncryptedData,\n BulkDecryptPayload,\n BulkDecryptedData,\n DecryptionResult,\n} from '@/types'\n\n// Query types (public only)\nexport type {\n QueryTypeName,\n EncryptQueryOptions,\n ScalarQueryTerm,\n} from '@/types'\n\n// Logging\nexport type { LoggingConfig } from '@/utils/logger'\n\n// Runtime values\nexport { queryTypes } from '@/types'\n","import type {\n ProtectColumn,\n ProtectTable,\n ProtectTableColumn,\n ProtectValue,\n} from '@/schema'\nimport type { LoggingConfig } from '@/utils/logger'\nimport type {\n Encrypted as CipherStashEncrypted,\n JsPlaintext,\n QueryOpName,\n newClient,\n} from '@cipherstash/protect-ffi'\n\n// ---------------------------------------------------------------------------\n// Branded type utilities\n// ---------------------------------------------------------------------------\n\n/** Brand symbol for nominal typing */\ndeclare const __brand: unique symbol\n\n/** Creates a branded type that is structurally incompatible with the base type */\ntype Brand<T, B extends string> = T & { readonly [__brand]: B }\n\n// ---------------------------------------------------------------------------\n// Core types\n// ---------------------------------------------------------------------------\n\nexport type Client = Awaited<ReturnType<typeof newClient>> | undefined\n\n/** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */\nexport type EncryptedValue = Brand<CipherStashEncrypted, 'encrypted'> | null\n\n/** Structural type representing encrypted data. See also `EncryptedValue` for branded nominal typing. */\nexport type Encrypted = CipherStashEncrypted | null\n\nexport type EncryptPayload = JsPlaintext | null\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nexport type KeysetIdentifier = { name: string } | { id: string }\n\nexport type ClientConfig = {\n /**\n * The CipherStash workspace CRN (Cloud Resource Name).\n * Format: `crn:<region>.aws:<workspace-id>`.\n * Can also be set via the `CS_WORKSPACE_CRN` environment variable.\n * If omitted, the SDK reads from the environment or TOML config files.\n */\n workspaceCrn?: string\n\n /**\n * The API access key used for authenticating with the CipherStash API.\n * Can also be set via the `CS_CLIENT_ACCESS_KEY` environment variable.\n * Obtain this from the CipherStash dashboard after creating a workspace.\n */\n accessKey?: string\n\n /**\n * The client identifier used to authenticate with CipherStash services.\n * Can also be set via the `CS_CLIENT_ID` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientId?: string\n\n /**\n * The client key material used in combination with ZeroKMS for encryption operations.\n * Can also be set via the `CS_CLIENT_KEY` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientKey?: string\n\n /**\n * An optional keyset identifier for multi-tenant encryption.\n * Each keyset provides cryptographic isolation, giving each tenant its own keyspace.\n * Specify by name (`{ name: \"tenant-a\" }`) or UUID (`{ id: \"...\" }`).\n * Keysets are created and managed in the CipherStash dashboard.\n */\n keyset?: KeysetIdentifier\n}\n\ntype AtLeastOneCsTable<T> = [T, ...T[]]\n\nexport type EncryptionClientConfig = {\n schemas: AtLeastOneCsTable<ProtectTable<ProtectTableColumn>>\n config?: ClientConfig\n logging?: LoggingConfig\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt operation options and results\n// ---------------------------------------------------------------------------\n\nexport type EncryptOptions = {\n column: ProtectColumn | ProtectValue\n table: ProtectTable<ProtectTableColumn>\n}\n\n/** Format for encrypted query/search term return values */\nexport type EncryptedReturnType =\n | 'eql'\n | 'composite-literal'\n | 'escaped-composite-literal'\n\nexport type SearchTerm = {\n value: JsPlaintext\n column: ProtectColumn\n table: ProtectTable<ProtectTableColumn>\n returnType?: EncryptedReturnType\n}\n\n/** Encrypted search term result: EQL object or composite literal string */\nexport type EncryptedSearchTerm = Encrypted | string\n\n/** Result of encryptQuery (single or batch): EQL, composite literal string, or null */\nexport type EncryptedQueryResult = Encrypted | string | null\n\n// ---------------------------------------------------------------------------\n// Model field types (encrypted vs decrypted views)\n// ---------------------------------------------------------------------------\n\nexport type EncryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: T[K]\n}\n\nexport type OtherFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? never : K]: T[K]\n}\n\nexport type DecryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: string\n}\n\n/** Model with encrypted fields replaced by plaintext (decrypted) values */\nexport type Decrypted<T> = OtherFields<T> & DecryptedFields<T>\n\n/**\n * Maps a plaintext model type to its encrypted form using the table schema.\n *\n * Fields whose keys match columns defined in `S` become `Encrypted`;\n * all other fields retain their original types from `T`.\n *\n * When `S` is the widened `ProtectTableColumn` (e.g. when a user passes an\n * explicit `<User>` type argument without specifying `S`), the type degrades\n * gracefully to `T` — preserving backward compatibility.\n *\n * @typeParam T - The plaintext model type (e.g. `{ id: string; email: string }`)\n * @typeParam S - The table schema column definition, inferred from the `table` argument\n *\n * @example\n * ```typescript\n * type User = { id: string; email: string }\n * // With a schema that defines `email`:\n * type Encrypted = EncryptedFromSchema<User, { email: ProtectColumn }>\n * // => { id: string; email: Encrypted }\n * ```\n */\nexport type EncryptedFromSchema<\n T,\n S extends ProtectTableColumn,\n> = {\n [K in keyof T]: [K] extends [keyof S]\n ? [S[K & keyof S]] extends [ProtectColumn | ProtectValue]\n ? Encrypted\n : T[K]\n : T[K]\n}\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\nexport type BulkEncryptPayload = Array<{\n id?: string\n plaintext: JsPlaintext | null\n}>\n\nexport type BulkEncryptedData = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptPayload = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptedData = Array<DecryptionResult<JsPlaintext | null>>\n\ntype DecryptionSuccess<T> = { error?: never; data: T; id?: string }\ntype DecryptionError<T> = { error: T; id?: string; data?: never }\n\n/**\n * Result type for individual items in bulk decrypt operations.\n * Uses `error`/`data` fields (not `failure`/`data`) since bulk operations\n * can have per-item failures.\n */\nexport type DecryptionResult<T> = DecryptionSuccess<T> | DecryptionError<T>\n\n// ---------------------------------------------------------------------------\n// Query types (for searchable encryption / encryptQuery)\n// ---------------------------------------------------------------------------\n\n/**\n * User-facing query type names for encrypting query values.\n *\n * - `'equality'`: Exact match. [Exact Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/exact)\n * - `'freeTextSearch'`: Text search. [Match Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/match)\n * - `'orderAndRange'`: Comparison and range. [Range Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/range)\n * - `'steVecSelector'`: JSONPath selector (e.g. `'$.user.email'`)\n * - `'steVecTerm'`: Containment (e.g. `{ role: 'admin' }`)\n * - `'searchableJson'`: Auto-infers selector or term from plaintext type (recommended)\n */\nexport type QueryTypeName =\n | 'orderAndRange'\n | 'freeTextSearch'\n | 'equality'\n | 'steVecSelector'\n | 'steVecTerm'\n | 'searchableJson'\n\n/** @internal */\nexport type FfiIndexTypeName = 'ore' | 'match' | 'unique' | 'ste_vec'\n\nexport const queryTypes = {\n orderAndRange: 'orderAndRange',\n freeTextSearch: 'freeTextSearch',\n equality: 'equality',\n steVecSelector: 'steVecSelector',\n steVecTerm: 'steVecTerm',\n searchableJson: 'searchableJson',\n} as const satisfies Record<string, QueryTypeName>\n\n/** @internal */\nexport const queryTypeToFfi: Record<QueryTypeName, FfiIndexTypeName> = {\n orderAndRange: 'ore',\n freeTextSearch: 'match',\n equality: 'unique',\n steVecSelector: 'ste_vec',\n steVecTerm: 'ste_vec',\n searchableJson: 'ste_vec',\n}\n\n/** @internal */\nexport const queryTypeToQueryOp: Partial<Record<QueryTypeName, QueryOpName>> = {\n steVecSelector: 'ste_vec_selector',\n steVecTerm: 'ste_vec_term',\n}\n\n/** @internal */\nexport type QueryTermBase = {\n column: ProtectColumn\n table: ProtectTable<ProtectTableColumn>\n queryType?: QueryTypeName\n returnType?: EncryptedReturnType\n}\n\nexport type EncryptQueryOptions = QueryTermBase\n\nexport type ScalarQueryTerm = QueryTermBase & {\n value: JsPlaintext | null\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC0NO,IAAM,aAAa;AAAA,EACxB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;","names":[]}
1
+ {"version":3,"sources":["../src/types-public.ts","../src/types.ts"],"sourcesContent":["/**\n * Public type re-exports for `@cipherstash/stack/types`.\n *\n * This module exposes only the public types from the internal types module.\n * Internal helpers (`queryTypeToFfi`, `queryTypeToQueryOp`, `FfiIndexTypeName`,\n * `QueryTermBase`) are excluded.\n */\n\n// Core types\nexport type {\n Client,\n EncryptedValue,\n Encrypted,\n} from '@/types'\n\n// Client configuration\nexport type {\n KeysetIdentifier,\n ClientConfig,\n EncryptionClientConfig,\n} from '@/types'\n\n// Encrypt / decrypt operation options and results\nexport type {\n EncryptOptions,\n EncryptedReturnType,\n SearchTerm,\n EncryptedSearchTerm,\n EncryptedQueryResult,\n} from '@/types'\n\n// Model field types\nexport type {\n EncryptedFields,\n OtherFields,\n DecryptedFields,\n Decrypted,\n} from '@/types'\n\n// Bulk operations\nexport type {\n BulkEncryptPayload,\n BulkEncryptedData,\n BulkDecryptPayload,\n BulkDecryptedData,\n DecryptionResult,\n} from '@/types'\n\n// Query types (public only)\nexport type {\n QueryTypeName,\n EncryptQueryOptions,\n ScalarQueryTerm,\n} from '@/types'\n\n// Logging\nexport type { LoggingConfig } from '@/utils/logger'\n\n// Runtime values\nexport { queryTypes } from '@/types'\n","import type {\n EncryptedColumn,\n EncryptedTable,\n EncryptedTableColumn,\n EncryptedField,\n} from '@/schema'\nimport type { LoggingConfig } from '@/utils/logger'\nimport type {\n Encrypted as CipherStashEncrypted,\n JsPlaintext,\n QueryOpName,\n newClient,\n} from '@cipherstash/protect-ffi'\n\n// ---------------------------------------------------------------------------\n// Branded type utilities\n// ---------------------------------------------------------------------------\n\n/** Brand symbol for nominal typing */\ndeclare const __brand: unique symbol\n\n/** Creates a branded type that is structurally incompatible with the base type */\ntype Brand<T, B extends string> = T & { readonly [__brand]: B }\n\n// ---------------------------------------------------------------------------\n// Core types\n// ---------------------------------------------------------------------------\n\nexport type Client = Awaited<ReturnType<typeof newClient>> | undefined\n\n/** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */\nexport type EncryptedValue = Brand<CipherStashEncrypted, 'encrypted'>\n\n/** Structural type representing encrypted data. See also `EncryptedValue` for branded nominal typing. */\nexport type Encrypted = CipherStashEncrypted\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nexport type KeysetIdentifier = { name: string } | { id: string }\n\nexport type ClientConfig = {\n /**\n * The CipherStash workspace CRN (Cloud Resource Name).\n * Format: `crn:<region>.aws:<workspace-id>`.\n * Can also be set via the `CS_WORKSPACE_CRN` environment variable.\n * If omitted, the SDK reads from the environment or TOML config files.\n */\n workspaceCrn?: string\n\n /**\n * The API access key used for authenticating with the CipherStash API.\n * Can also be set via the `CS_CLIENT_ACCESS_KEY` environment variable.\n * Obtain this from the CipherStash dashboard after creating a workspace.\n */\n accessKey?: string\n\n /**\n * The client identifier used to authenticate with CipherStash services.\n * Can also be set via the `CS_CLIENT_ID` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientId?: string\n\n /**\n * The client key material used in combination with ZeroKMS for encryption operations.\n * Can also be set via the `CS_CLIENT_KEY` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientKey?: string\n\n /**\n * An optional keyset identifier for multi-tenant encryption.\n * Each keyset provides cryptographic isolation, giving each tenant its own keyspace.\n * Specify by name (`{ name: \"tenant-a\" }`) or UUID (`{ id: \"...\" }`).\n * Keysets are created and managed in the CipherStash dashboard.\n */\n keyset?: KeysetIdentifier\n}\n\ntype AtLeastOneCsTable<T> = [T, ...T[]]\n\nexport type EncryptionClientConfig = {\n schemas: AtLeastOneCsTable<EncryptedTable<EncryptedTableColumn>>\n config?: ClientConfig\n logging?: LoggingConfig\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt operation options and results\n// ---------------------------------------------------------------------------\n\n/**\n * Options for single-value encrypt operations.\n * Use a column from your table schema (from {@link encryptedColumn}) or a nested\n * field (from {@link encryptedField}) as the target for encryption.\n */\nexport type EncryptOptions = {\n /** The column or nested field to encrypt into. From {@link EncryptedColumn} or {@link EncryptedField}. */\n column: EncryptedColumn | EncryptedField\n table: EncryptedTable<EncryptedTableColumn>\n}\n\n/** Format for encrypted query/search term return values */\nexport type EncryptedReturnType =\n | 'eql'\n | 'composite-literal'\n | 'escaped-composite-literal'\n\nexport type SearchTerm = {\n value: JsPlaintext\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n returnType?: EncryptedReturnType\n}\n\n/** Encrypted search term result: EQL object or composite literal string */\nexport type EncryptedSearchTerm = Encrypted | string\n\n/** Result of encryptQuery (single or batch): EQL or composite literal string */\nexport type EncryptedQueryResult = Encrypted | string\n\n// ---------------------------------------------------------------------------\n// Model field types (encrypted vs decrypted views)\n// ---------------------------------------------------------------------------\n\nexport type EncryptedFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? K : never]: T[K]\n}\n\nexport type OtherFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? never : K]: T[K]\n}\n\nexport type DecryptedFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? K : never]:\n null extends T[K] ? string | null : string\n}\n\n/** Model with encrypted fields replaced by plaintext (decrypted) values */\nexport type Decrypted<T> = OtherFields<T> & DecryptedFields<T>\n\n/**\n * Maps a plaintext model type to its encrypted form using the table schema.\n *\n * Fields whose keys match columns defined in `S` become `Encrypted`;\n * all other fields retain their original types from `T`.\n *\n * When `S` is the widened `EncryptedTableColumn` (e.g. when a user passes an\n * explicit `<User>` type argument without specifying `S`), the type degrades\n * gracefully to `T` — preserving backward compatibility.\n *\n * @typeParam T - The plaintext model type (e.g. `{ id: string; email: string }`)\n * @typeParam S - The table schema column definition, inferred from the `table` argument\n *\n * @example\n * ```typescript\n * type User = { id: string; email: string }\n * // With a schema that defines `email`:\n * type Encrypted = EncryptedFromSchema<User, { email: EncryptedColumn }>\n * // => { id: string; email: Encrypted }\n * ```\n */\nexport type EncryptedFromSchema<T, S extends EncryptedTableColumn> = {\n [K in keyof T]: [K] extends [keyof S]\n ? [S[K & keyof S]] extends [EncryptedColumn | EncryptedField]\n ? null extends T[K] ? Encrypted | null : Encrypted\n : T[K]\n : T[K]\n}\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\nexport type BulkEncryptPayload = Array<{\n id?: string\n plaintext: JsPlaintext\n}>\n\nexport type BulkEncryptedData = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptPayload = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptedData = Array<DecryptionResult<JsPlaintext>>\n\ntype DecryptionSuccess<T> = { error?: never; data: T; id?: string }\ntype DecryptionError<T> = { error: T; id?: string; data?: never }\n\n/**\n * Result type for individual items in bulk decrypt operations.\n * Uses `error`/`data` fields (not `failure`/`data`) since bulk operations\n * can have per-item failures.\n */\nexport type DecryptionResult<T> = DecryptionSuccess<T> | DecryptionError<T>\n\n// ---------------------------------------------------------------------------\n// Query types (for searchable encryption / encryptQuery)\n// ---------------------------------------------------------------------------\n\n/**\n * User-facing query type names for encrypting query values.\n *\n * - `'equality'`: Exact match. [Exact Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/exact)\n * - `'freeTextSearch'`: Text search. [Match Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/match)\n * - `'orderAndRange'`: Comparison and range. [Range Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/range)\n * - `'steVecSelector'`: JSONPath selector (e.g. `'$.user.email'`)\n * - `'steVecTerm'`: Containment (e.g. `{ role: 'admin' }`)\n * - `'searchableJson'`: Auto-infers selector or term from plaintext type (recommended)\n */\nexport type QueryTypeName =\n | 'orderAndRange'\n | 'freeTextSearch'\n | 'equality'\n | 'steVecSelector'\n | 'steVecTerm'\n | 'searchableJson'\n\n/** @internal */\nexport type FfiIndexTypeName = 'ore' | 'match' | 'unique' | 'ste_vec'\n\nexport const queryTypes = {\n orderAndRange: 'orderAndRange',\n freeTextSearch: 'freeTextSearch',\n equality: 'equality',\n steVecSelector: 'steVecSelector',\n steVecTerm: 'steVecTerm',\n searchableJson: 'searchableJson',\n} as const satisfies Record<string, QueryTypeName>\n\n/** @internal */\nexport const queryTypeToFfi: Record<QueryTypeName, FfiIndexTypeName> = {\n orderAndRange: 'ore',\n freeTextSearch: 'match',\n equality: 'unique',\n steVecSelector: 'ste_vec',\n steVecTerm: 'ste_vec',\n searchableJson: 'ste_vec',\n}\n\n/** @internal */\nexport const queryTypeToQueryOp: Partial<Record<QueryTypeName, QueryOpName>> = {\n steVecSelector: 'ste_vec_selector',\n steVecTerm: 'ste_vec_term',\n}\n\n/** @internal */\nexport type QueryTermBase = {\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n queryType?: QueryTypeName\n returnType?: EncryptedReturnType\n}\n\nexport type EncryptQueryOptions = QueryTermBase\n\nexport type ScalarQueryTerm = QueryTermBase & {\n value: JsPlaintext\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC4NO,IAAM,aAAa;AAAA,EACxB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;","names":[]}
@@ -1,4 +1,4 @@
1
- export { m as BulkDecryptPayload, B as BulkDecryptedData, o as BulkEncryptPayload, n as BulkEncryptedData, l as Client, z as ClientConfig, D as Decrypted, J as DecryptedFields, L as DecryptionResult, p as EncryptOptions, y as EncryptPayload, q as EncryptQueryOptions, i as Encrypted, G as EncryptedFields, k as EncryptedQueryResult, r as EncryptedReturnType, F as EncryptedSearchTerm, j as EncryptedValue, E as EncryptionClientConfig, K as KeysetIdentifier, N as LoggingConfig, H as OtherFields, Q as QueryTypeName, S as ScalarQueryTerm, A as SearchTerm, R as queryTypes } from './types-public-Dfg-hkuQ.cjs';
1
+ export { n as BulkDecryptPayload, B as BulkDecryptedData, p as BulkEncryptPayload, o as BulkEncryptedData, m as Client, z as ClientConfig, D as Decrypted, J as DecryptedFields, L as DecryptionResult, q as EncryptOptions, r as EncryptQueryOptions, j as Encrypted, G as EncryptedFields, l as EncryptedQueryResult, s as EncryptedReturnType, F as EncryptedSearchTerm, k as EncryptedValue, E as EncryptionClientConfig, K as KeysetIdentifier, N as LoggingConfig, H as OtherFields, Q as QueryTypeName, S as ScalarQueryTerm, A as SearchTerm, P as queryTypes } from './types-public-Wj6tB_ux.cjs';
2
2
  import 'zod';
3
3
  import 'evlog';
4
4
  import '@cipherstash/protect-ffi';
@@ -1,4 +1,4 @@
1
- export { m as BulkDecryptPayload, B as BulkDecryptedData, o as BulkEncryptPayload, n as BulkEncryptedData, l as Client, z as ClientConfig, D as Decrypted, J as DecryptedFields, L as DecryptionResult, p as EncryptOptions, y as EncryptPayload, q as EncryptQueryOptions, i as Encrypted, G as EncryptedFields, k as EncryptedQueryResult, r as EncryptedReturnType, F as EncryptedSearchTerm, j as EncryptedValue, E as EncryptionClientConfig, K as KeysetIdentifier, N as LoggingConfig, H as OtherFields, Q as QueryTypeName, S as ScalarQueryTerm, A as SearchTerm, R as queryTypes } from './types-public-Dfg-hkuQ.js';
1
+ export { n as BulkDecryptPayload, B as BulkDecryptedData, p as BulkEncryptPayload, o as BulkEncryptedData, m as Client, z as ClientConfig, D as Decrypted, J as DecryptedFields, L as DecryptionResult, q as EncryptOptions, r as EncryptQueryOptions, j as Encrypted, G as EncryptedFields, l as EncryptedQueryResult, s as EncryptedReturnType, F as EncryptedSearchTerm, k as EncryptedValue, E as EncryptionClientConfig, K as KeysetIdentifier, N as LoggingConfig, H as OtherFields, Q as QueryTypeName, S as ScalarQueryTerm, A as SearchTerm, P as queryTypes } from './types-public-Wj6tB_ux.js';
2
2
  import 'zod';
3
3
  import 'evlog';
4
4
  import '@cipherstash/protect-ffi';
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  queryTypes
3
- } from "./chunk-5G4F4JJG.js";
3
+ } from "./chunk-KOU2MHXJ.js";
4
4
  export {
5
5
  queryTypes
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cipherstash/stack",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "CipherStash Stack for TypeScript and JavaScript",
5
5
  "keywords": [
6
6
  "encrypted",
@@ -173,7 +173,7 @@
173
173
  },
174
174
  "dependencies": {
175
175
  "@byteslice/result": "^0.2.0",
176
- "@cipherstash/protect-ffi": "0.20.1",
176
+ "@cipherstash/protect-ffi": "0.20.2",
177
177
  "evlog": "^1.9.0",
178
178
  "zod": "3.24.2"
179
179
  },
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n ProtectColumn,\n ProtectTable,\n ProtectTableColumn,\n ProtectValue,\n} from '@/schema'\nimport type { LoggingConfig } from '@/utils/logger'\nimport type {\n Encrypted as CipherStashEncrypted,\n JsPlaintext,\n QueryOpName,\n newClient,\n} from '@cipherstash/protect-ffi'\n\n// ---------------------------------------------------------------------------\n// Branded type utilities\n// ---------------------------------------------------------------------------\n\n/** Brand symbol for nominal typing */\ndeclare const __brand: unique symbol\n\n/** Creates a branded type that is structurally incompatible with the base type */\ntype Brand<T, B extends string> = T & { readonly [__brand]: B }\n\n// ---------------------------------------------------------------------------\n// Core types\n// ---------------------------------------------------------------------------\n\nexport type Client = Awaited<ReturnType<typeof newClient>> | undefined\n\n/** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */\nexport type EncryptedValue = Brand<CipherStashEncrypted, 'encrypted'> | null\n\n/** Structural type representing encrypted data. See also `EncryptedValue` for branded nominal typing. */\nexport type Encrypted = CipherStashEncrypted | null\n\nexport type EncryptPayload = JsPlaintext | null\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nexport type KeysetIdentifier = { name: string } | { id: string }\n\nexport type ClientConfig = {\n /**\n * The CipherStash workspace CRN (Cloud Resource Name).\n * Format: `crn:<region>.aws:<workspace-id>`.\n * Can also be set via the `CS_WORKSPACE_CRN` environment variable.\n * If omitted, the SDK reads from the environment or TOML config files.\n */\n workspaceCrn?: string\n\n /**\n * The API access key used for authenticating with the CipherStash API.\n * Can also be set via the `CS_CLIENT_ACCESS_KEY` environment variable.\n * Obtain this from the CipherStash dashboard after creating a workspace.\n */\n accessKey?: string\n\n /**\n * The client identifier used to authenticate with CipherStash services.\n * Can also be set via the `CS_CLIENT_ID` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientId?: string\n\n /**\n * The client key material used in combination with ZeroKMS for encryption operations.\n * Can also be set via the `CS_CLIENT_KEY` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientKey?: string\n\n /**\n * An optional keyset identifier for multi-tenant encryption.\n * Each keyset provides cryptographic isolation, giving each tenant its own keyspace.\n * Specify by name (`{ name: \"tenant-a\" }`) or UUID (`{ id: \"...\" }`).\n * Keysets are created and managed in the CipherStash dashboard.\n */\n keyset?: KeysetIdentifier\n}\n\ntype AtLeastOneCsTable<T> = [T, ...T[]]\n\nexport type EncryptionClientConfig = {\n schemas: AtLeastOneCsTable<ProtectTable<ProtectTableColumn>>\n config?: ClientConfig\n logging?: LoggingConfig\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt operation options and results\n// ---------------------------------------------------------------------------\n\nexport type EncryptOptions = {\n column: ProtectColumn | ProtectValue\n table: ProtectTable<ProtectTableColumn>\n}\n\n/** Format for encrypted query/search term return values */\nexport type EncryptedReturnType =\n | 'eql'\n | 'composite-literal'\n | 'escaped-composite-literal'\n\nexport type SearchTerm = {\n value: JsPlaintext\n column: ProtectColumn\n table: ProtectTable<ProtectTableColumn>\n returnType?: EncryptedReturnType\n}\n\n/** Encrypted search term result: EQL object or composite literal string */\nexport type EncryptedSearchTerm = Encrypted | string\n\n/** Result of encryptQuery (single or batch): EQL, composite literal string, or null */\nexport type EncryptedQueryResult = Encrypted | string | null\n\n// ---------------------------------------------------------------------------\n// Model field types (encrypted vs decrypted views)\n// ---------------------------------------------------------------------------\n\nexport type EncryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: T[K]\n}\n\nexport type OtherFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? never : K]: T[K]\n}\n\nexport type DecryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: string\n}\n\n/** Model with encrypted fields replaced by plaintext (decrypted) values */\nexport type Decrypted<T> = OtherFields<T> & DecryptedFields<T>\n\n/**\n * Maps a plaintext model type to its encrypted form using the table schema.\n *\n * Fields whose keys match columns defined in `S` become `Encrypted`;\n * all other fields retain their original types from `T`.\n *\n * When `S` is the widened `ProtectTableColumn` (e.g. when a user passes an\n * explicit `<User>` type argument without specifying `S`), the type degrades\n * gracefully to `T` — preserving backward compatibility.\n *\n * @typeParam T - The plaintext model type (e.g. `{ id: string; email: string }`)\n * @typeParam S - The table schema column definition, inferred from the `table` argument\n *\n * @example\n * ```typescript\n * type User = { id: string; email: string }\n * // With a schema that defines `email`:\n * type Encrypted = EncryptedFromSchema<User, { email: ProtectColumn }>\n * // => { id: string; email: Encrypted }\n * ```\n */\nexport type EncryptedFromSchema<\n T,\n S extends ProtectTableColumn,\n> = {\n [K in keyof T]: [K] extends [keyof S]\n ? [S[K & keyof S]] extends [ProtectColumn | ProtectValue]\n ? Encrypted\n : T[K]\n : T[K]\n}\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\nexport type BulkEncryptPayload = Array<{\n id?: string\n plaintext: JsPlaintext | null\n}>\n\nexport type BulkEncryptedData = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptPayload = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptedData = Array<DecryptionResult<JsPlaintext | null>>\n\ntype DecryptionSuccess<T> = { error?: never; data: T; id?: string }\ntype DecryptionError<T> = { error: T; id?: string; data?: never }\n\n/**\n * Result type for individual items in bulk decrypt operations.\n * Uses `error`/`data` fields (not `failure`/`data`) since bulk operations\n * can have per-item failures.\n */\nexport type DecryptionResult<T> = DecryptionSuccess<T> | DecryptionError<T>\n\n// ---------------------------------------------------------------------------\n// Query types (for searchable encryption / encryptQuery)\n// ---------------------------------------------------------------------------\n\n/**\n * User-facing query type names for encrypting query values.\n *\n * - `'equality'`: Exact match. [Exact Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/exact)\n * - `'freeTextSearch'`: Text search. [Match Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/match)\n * - `'orderAndRange'`: Comparison and range. [Range Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/range)\n * - `'steVecSelector'`: JSONPath selector (e.g. `'$.user.email'`)\n * - `'steVecTerm'`: Containment (e.g. `{ role: 'admin' }`)\n * - `'searchableJson'`: Auto-infers selector or term from plaintext type (recommended)\n */\nexport type QueryTypeName =\n | 'orderAndRange'\n | 'freeTextSearch'\n | 'equality'\n | 'steVecSelector'\n | 'steVecTerm'\n | 'searchableJson'\n\n/** @internal */\nexport type FfiIndexTypeName = 'ore' | 'match' | 'unique' | 'ste_vec'\n\nexport const queryTypes = {\n orderAndRange: 'orderAndRange',\n freeTextSearch: 'freeTextSearch',\n equality: 'equality',\n steVecSelector: 'steVecSelector',\n steVecTerm: 'steVecTerm',\n searchableJson: 'searchableJson',\n} as const satisfies Record<string, QueryTypeName>\n\n/** @internal */\nexport const queryTypeToFfi: Record<QueryTypeName, FfiIndexTypeName> = {\n orderAndRange: 'ore',\n freeTextSearch: 'match',\n equality: 'unique',\n steVecSelector: 'ste_vec',\n steVecTerm: 'ste_vec',\n searchableJson: 'ste_vec',\n}\n\n/** @internal */\nexport const queryTypeToQueryOp: Partial<Record<QueryTypeName, QueryOpName>> = {\n steVecSelector: 'ste_vec_selector',\n steVecTerm: 'ste_vec_term',\n}\n\n/** @internal */\nexport type QueryTermBase = {\n column: ProtectColumn\n table: ProtectTable<ProtectTableColumn>\n queryType?: QueryTypeName\n returnType?: EncryptedReturnType\n}\n\nexport type EncryptQueryOptions = QueryTermBase\n\nexport type ScalarQueryTerm = QueryTermBase & {\n value: JsPlaintext | null\n}\n"],"mappings":";AA0NO,IAAM,aAAa;AAAA,EACxB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAGO,IAAM,iBAA0D;AAAA,EACrE,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAGO,IAAM,qBAAkE;AAAA,EAC7E,gBAAgB;AAAA,EAChB,YAAY;AACd;","names":[]}