@cipherstash/protect-ffi 0.19.0 → 0.20.1

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.
package/README.md CHANGED
@@ -38,12 +38,27 @@ $ npm i
38
38
  $ npm run build
39
39
  $ node
40
40
  > const addon = require(".");
41
- > const client = await addon.newClient(JSON.stringify({v: 1, tables: {users: {email: {indexes: {ore: {}, match: {}, unique: {}}}}}}));
42
- > const ciphertext = await addon.encrypt(client, "plaintext", "email", "users");
43
- > const plaintext = await addon.decrypt(client, JSON.parse(ciphertext).c);
41
+ > const client = await addon.newClient({ encryptConfig: {v: 1, tables: {users: {email: {indexes: {ore: {}, match: {}, unique: {}}}}}} });
42
+ > const ciphertext = await addon.encrypt(client, { plaintext: "plaintext", column: "email", table: "users" });
43
+ > const plaintext = await addon.decrypt(client, { ciphertext });
44
44
  > console.log({ciphertext, plaintext});
45
45
  ```
46
46
 
47
+ ## Errors
48
+
49
+ Async API calls throw `ProtectError` with a stable `code` for programmatic handling.
50
+
51
+ ```typescript
52
+ try {
53
+ await addon.encryptQuery(client, opts)
54
+ } catch (err) {
55
+ if (err?.code === 'INVALID_JSON_PATH') {
56
+ // handle JSON path mistakes
57
+ }
58
+ throw err
59
+ }
60
+ ```
61
+
47
62
  ## Available Scripts
48
63
 
49
64
  In the project directory, you can run:
package/lib/index.cjs CHANGED
@@ -1,12 +1,146 @@
1
1
  "use strict";
2
2
  // This module is the CJS entry point for the library.
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
3
36
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.decryptBulkFallible = exports.decryptBulk = exports.decrypt = exports.isEncrypted = exports.encryptBulk = exports.encrypt = exports.newClient = void 0;
5
- var load_cjs_1 = require("./load.cjs");
6
- Object.defineProperty(exports, "newClient", { enumerable: true, get: function () { return load_cjs_1.newClient; } });
7
- Object.defineProperty(exports, "encrypt", { enumerable: true, get: function () { return load_cjs_1.encrypt; } });
8
- Object.defineProperty(exports, "encryptBulk", { enumerable: true, get: function () { return load_cjs_1.encryptBulk; } });
9
- Object.defineProperty(exports, "isEncrypted", { enumerable: true, get: function () { return load_cjs_1.isEncrypted; } });
10
- Object.defineProperty(exports, "decrypt", { enumerable: true, get: function () { return load_cjs_1.decrypt; } });
11
- Object.defineProperty(exports, "decryptBulk", { enumerable: true, get: function () { return load_cjs_1.decryptBulk; } });
12
- Object.defineProperty(exports, "decryptBulkFallible", { enumerable: true, get: function () { return load_cjs_1.decryptBulkFallible; } });
37
+ exports.ProtectError = void 0;
38
+ exports.newClient = newClient;
39
+ exports.encrypt = encrypt;
40
+ exports.decrypt = decrypt;
41
+ exports.isEncrypted = isEncrypted;
42
+ exports.encryptBulk = encryptBulk;
43
+ exports.decryptBulk = decryptBulk;
44
+ exports.decryptBulkFallible = decryptBulkFallible;
45
+ exports.encryptQuery = encryptQuery;
46
+ exports.encryptQueryBulk = encryptQueryBulk;
47
+ const native = __importStar(require("./load.cjs"));
48
+ class ProtectError extends Error {
49
+ code;
50
+ details;
51
+ cause;
52
+ constructor(opts) {
53
+ super(opts.message);
54
+ this.name = 'ProtectError';
55
+ this.code = opts.code;
56
+ this.details = opts.details;
57
+ this.cause = opts.cause;
58
+ }
59
+ }
60
+ exports.ProtectError = ProtectError;
61
+ function inferErrorCode(message) {
62
+ if (message.startsWith('protect-ffi invariant violation:')) {
63
+ return 'INVARIANT_VIOLATION';
64
+ }
65
+ if (message.startsWith('Unknown query operation:')) {
66
+ return 'UNKNOWN_QUERY_OP';
67
+ }
68
+ if (message.startsWith('Invalid query input for')) {
69
+ return 'INVALID_QUERY_INPUT';
70
+ }
71
+ if (message.startsWith('Invalid JSON path')) {
72
+ return 'INVALID_JSON_PATH';
73
+ }
74
+ if (message.includes(' not found in Encrypt config')) {
75
+ return 'UNKNOWN_COLUMN';
76
+ }
77
+ if (message.includes(' index configured')) {
78
+ return 'MISSING_INDEX';
79
+ }
80
+ if (message.includes("ste_vec index requires cast_as: 'json'")) {
81
+ return 'STE_VEC_REQUIRES_JSON_CAST_AS';
82
+ }
83
+ return 'UNKNOWN';
84
+ }
85
+ function normalizeError(err) {
86
+ if (err instanceof ProtectError) {
87
+ return err;
88
+ }
89
+ if (err && typeof err === 'object' && 'message' in err) {
90
+ const message = String(err.message ?? 'Unknown error');
91
+ const code = inferErrorCode(message);
92
+ if (code !== 'UNKNOWN') {
93
+ return new ProtectError({ code, message, cause: err });
94
+ }
95
+ }
96
+ return err;
97
+ }
98
+ async function wrapAsync(fn) {
99
+ try {
100
+ return await fn();
101
+ }
102
+ catch (err) {
103
+ throw normalizeError(err);
104
+ }
105
+ }
106
+ function wrapSync(fn) {
107
+ try {
108
+ return fn();
109
+ }
110
+ catch (err) {
111
+ throw normalizeError(err);
112
+ }
113
+ }
114
+ function newClient(opts) {
115
+ return wrapAsync(() => native.newClient(opts));
116
+ }
117
+ function encrypt(client, opts) {
118
+ return wrapAsync(() => native.encrypt(client, opts));
119
+ }
120
+ function decrypt(client, opts) {
121
+ return wrapAsync(() => native.decrypt(client, opts));
122
+ }
123
+ function isEncrypted(encrypted) {
124
+ return wrapSync(() => native.isEncrypted(encrypted));
125
+ }
126
+ function encryptBulk(client, opts) {
127
+ return wrapAsync(() => native.encryptBulk(client, opts));
128
+ }
129
+ function decryptBulk(client, opts) {
130
+ return wrapAsync(() => native.decryptBulk(client, opts));
131
+ }
132
+ async function decryptBulkFallible(client, opts) {
133
+ const results = await wrapAsync(() => native.decryptBulkFallible(client, opts));
134
+ return results.map((item) => {
135
+ if ('error' in item && typeof item.error === 'string') {
136
+ return { ...item, code: inferErrorCode(item.error) };
137
+ }
138
+ return item;
139
+ });
140
+ }
141
+ function encryptQuery(client, opts) {
142
+ return wrapAsync(() => native.encryptQuery(client, opts));
143
+ }
144
+ function encryptQueryBulk(client, opts) {
145
+ return wrapAsync(() => native.encryptQueryBulk(client, opts));
146
+ }
package/lib/index.d.cts CHANGED
@@ -1,4 +1,3 @@
1
- export { newClient, encrypt, encryptBulk, isEncrypted, decrypt, decryptBulk, decryptBulkFallible, } from './load.cjs';
2
1
  declare const sym: unique symbol;
3
2
  export type Client = {
4
3
  readonly [sym]: unknown;
@@ -11,12 +10,36 @@ declare module './load.cjs' {
11
10
  function encryptBulk(client: Client, opts: EncryptBulkOptions): Promise<Encrypted[]>;
12
11
  function decryptBulk(client: Client, opts: DecryptBulkOptions): Promise<JsPlaintext[]>;
13
12
  function decryptBulkFallible(client: Client, opts: DecryptBulkOptions): Promise<DecryptResult[]>;
13
+ function encryptQuery(client: Client, opts: EncryptQueryOptions): Promise<Encrypted>;
14
+ function encryptQueryBulk(client: Client, opts: EncryptQueryBulkOptions): Promise<Encrypted[]>;
15
+ }
16
+ export type ProtectErrorCode = 'INVARIANT_VIOLATION' | 'UNKNOWN_QUERY_OP' | 'UNKNOWN_COLUMN' | 'MISSING_INDEX' | 'INVALID_QUERY_INPUT' | 'INVALID_JSON_PATH' | 'STE_VEC_REQUIRES_JSON_CAST_AS' | 'UNKNOWN';
17
+ export declare class ProtectError extends Error {
18
+ code: ProtectErrorCode;
19
+ details?: unknown;
20
+ cause?: unknown;
21
+ constructor(opts: {
22
+ code: ProtectErrorCode;
23
+ message: string;
24
+ details?: unknown;
25
+ cause?: unknown;
26
+ });
14
27
  }
15
28
  export type DecryptResult = {
16
- data: string;
29
+ data: JsPlaintext;
17
30
  } | {
18
31
  error: string;
19
- };
32
+ code?: ProtectErrorCode;
33
+ };
34
+ export declare function newClient(opts: NewClientOptions): Promise<Client>;
35
+ export declare function encrypt(client: Client, opts: EncryptOptions): Promise<Encrypted>;
36
+ export declare function decrypt(client: Client, opts: DecryptOptions): Promise<JsPlaintext>;
37
+ export declare function isEncrypted(encrypted: Encrypted): boolean;
38
+ export declare function encryptBulk(client: Client, opts: EncryptBulkOptions): Promise<Encrypted[]>;
39
+ export declare function decryptBulk(client: Client, opts: DecryptBulkOptions): Promise<JsPlaintext[]>;
40
+ export declare function decryptBulkFallible(client: Client, opts: DecryptBulkOptions): Promise<DecryptResult[]>;
41
+ export declare function encryptQuery(client: Client, opts: EncryptQueryOptions): Promise<Encrypted>;
42
+ export declare function encryptQueryBulk(client: Client, opts: EncryptQueryBulkOptions): Promise<Encrypted[]>;
20
43
  export type EncryptPayload = {
21
44
  plaintext: JsPlaintext;
22
45
  column: string;
@@ -135,6 +158,7 @@ export type MatchIndexOpts = {
135
158
  };
136
159
  export type SteVecIndexOpts = {
137
160
  prefix: string;
161
+ term_filters?: TokenFilter[];
138
162
  };
139
163
  export type Tokenizer = {
140
164
  kind: 'standard';
@@ -161,7 +185,7 @@ export type KeysetIdentifier = {
161
185
  } | {
162
186
  Name: string;
163
187
  };
164
- export type JsPlaintext = string | number | Record<string, unknown> | JsPlaintext[];
188
+ export type JsPlaintext = string | number | boolean | Record<string, unknown> | JsPlaintext[];
165
189
  export type EncryptOptions = {
166
190
  plaintext: JsPlaintext;
167
191
  column: string;
@@ -186,3 +210,29 @@ export type DecryptBulkOptions = {
186
210
  serviceToken?: CtsToken;
187
211
  unverifiedContext?: Record<string, unknown>;
188
212
  };
213
+ export type IndexTypeName = 'ste_vec' | 'match' | 'ore' | 'unique';
214
+ export type QueryOpName = 'default' | 'ste_vec_selector' | 'ste_vec_term';
215
+ export type EncryptQueryOptions = {
216
+ plaintext: JsPlaintext;
217
+ column: string;
218
+ table: string;
219
+ indexType: IndexTypeName;
220
+ queryOp?: QueryOpName;
221
+ lockContext?: Context;
222
+ serviceToken?: CtsToken;
223
+ unverifiedContext?: Record<string, unknown>;
224
+ };
225
+ export type QueryPayload = {
226
+ plaintext: JsPlaintext;
227
+ column: string;
228
+ table: string;
229
+ indexType: IndexTypeName;
230
+ queryOp?: QueryOpName;
231
+ lockContext?: Context;
232
+ };
233
+ export type EncryptQueryBulkOptions = {
234
+ queries: QueryPayload[];
235
+ serviceToken?: CtsToken;
236
+ unverifiedContext?: Record<string, unknown>;
237
+ };
238
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cipherstash/protect-ffi",
3
- "version": "0.19.0",
3
+ "version": "0.20.1",
4
4
  "description": "",
5
5
  "main": "./lib/index.cjs",
6
6
  "scripts": {
@@ -67,11 +67,11 @@
67
67
  "@neon-rs/load": "^0.1.82"
68
68
  },
69
69
  "optionalDependencies": {
70
- "@cipherstash/protect-ffi-darwin-x64": "0.19.0",
71
- "@cipherstash/protect-ffi-darwin-arm64": "0.19.0",
72
- "@cipherstash/protect-ffi-win32-x64-msvc": "0.19.0",
73
- "@cipherstash/protect-ffi-linux-x64-gnu": "0.19.0",
74
- "@cipherstash/protect-ffi-linux-arm64-gnu": "0.19.0",
75
- "@cipherstash/protect-ffi-linux-x64-musl": "0.19.0"
70
+ "@cipherstash/protect-ffi-darwin-x64": "0.20.1",
71
+ "@cipherstash/protect-ffi-darwin-arm64": "0.20.1",
72
+ "@cipherstash/protect-ffi-win32-x64-msvc": "0.20.1",
73
+ "@cipherstash/protect-ffi-linux-x64-gnu": "0.20.1",
74
+ "@cipherstash/protect-ffi-linux-arm64-gnu": "0.20.1",
75
+ "@cipherstash/protect-ffi-linux-x64-musl": "0.20.1"
76
76
  }
77
77
  }