@ekodb/ekodb-client 0.15.2 → 0.17.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.
@@ -1,7 +1,9 @@
1
1
  /**
2
- * Scripts API for ekoDB TypeScript client
2
+ * Functions API for ekoDB TypeScript client
3
3
  */
4
- export interface Script {
4
+ /** A reusable sequence of Functions stored in ekoDB. */
5
+ export interface UserFunction {
6
+ id?: string;
5
7
  label: string;
6
8
  name: string;
7
9
  description?: string;
@@ -140,7 +142,7 @@ export type FunctionStageConfig = {
140
142
  value: any;
141
143
  } | {
142
144
  type: "If";
143
- condition: ScriptCondition;
145
+ condition: FunctionCondition;
144
146
  then_functions: FunctionStageConfig[];
145
147
  else_functions?: FunctionStageConfig[];
146
148
  } | {
@@ -205,6 +207,72 @@ export type FunctionStageConfig = {
205
207
  timeout_seconds?: number;
206
208
  output_field?: string;
207
209
  collection?: string;
210
+ } | {
211
+ /**
212
+ * Bcrypt-hash a plaintext value and add the result to every record in
213
+ * the working data as `output_field`. Requires ekoDB >= 0.41.0.
214
+ */
215
+ type: "BcryptHash";
216
+ plain: string;
217
+ cost?: number;
218
+ output_field: string;
219
+ } | {
220
+ /**
221
+ * Verify a plaintext against a bcrypt hash stored on the first record
222
+ * in the working data and write a boolean result into `output_field`.
223
+ * Pair with an `If` stage for login flows. Requires ekoDB >= 0.41.0.
224
+ */
225
+ type: "BcryptVerify";
226
+ plain: string;
227
+ hash_field: string;
228
+ output_field: string;
229
+ } | {
230
+ /**
231
+ * Generate a cryptographically-random token and add it to every
232
+ * record in the working data. Requires ekoDB >= 0.41.0.
233
+ */
234
+ type: "RandomToken";
235
+ bytes: number;
236
+ encoding?: "hex" | "base64" | "base64url";
237
+ output_field: string;
238
+ } | {
239
+ /**
240
+ * Try/Catch error handling for graceful failure recovery.
241
+ * Executes try_functions, and if any fail, executes catch_functions.
242
+ */
243
+ type: "TryCatch";
244
+ try_functions: FunctionStageConfig[];
245
+ catch_functions: FunctionStageConfig[];
246
+ output_error_field?: string;
247
+ } | {
248
+ /**
249
+ * Execute multiple functions in parallel (concurrently).
250
+ * All functions run simultaneously, results are merged.
251
+ */
252
+ type: "Parallel";
253
+ functions: FunctionStageConfig[];
254
+ wait_for_all: boolean;
255
+ } | {
256
+ /** Sleep/delay execution for rate limiting or timing control. */
257
+ type: "Sleep";
258
+ duration_ms: string | number;
259
+ } | {
260
+ /**
261
+ * Return a shaped response (final output formatting).
262
+ * Constructs the final response object from current execution context.
263
+ */
264
+ type: "Return";
265
+ fields: Record<string, any>;
266
+ status_code?: number;
267
+ } | {
268
+ /**
269
+ * Validate data against a JSON schema before processing.
270
+ * Prevents invalid data from corrupting database or causing errors downstream.
271
+ */
272
+ type: "Validate";
273
+ schema: Record<string, any>;
274
+ data_field: string;
275
+ on_error?: FunctionStageConfig[];
208
276
  };
209
277
  export interface ChatMessage {
210
278
  role: string;
@@ -224,7 +292,7 @@ export interface SortFieldConfig {
224
292
  field: string;
225
293
  ascending: boolean;
226
294
  }
227
- export type ScriptCondition = {
295
+ export type FunctionCondition = {
228
296
  type: "FieldEquals";
229
297
  value: {
230
298
  field: string;
@@ -255,17 +323,17 @@ export type ScriptCondition = {
255
323
  } | {
256
324
  type: "And";
257
325
  value: {
258
- conditions: ScriptCondition[];
326
+ conditions: FunctionCondition[];
259
327
  };
260
328
  } | {
261
329
  type: "Or";
262
330
  value: {
263
- conditions: ScriptCondition[];
331
+ conditions: FunctionCondition[];
264
332
  };
265
333
  } | {
266
334
  type: "Not";
267
335
  value: {
268
- condition: ScriptCondition;
336
+ condition: FunctionCondition;
269
337
  };
270
338
  };
271
339
  export interface FunctionResult {
@@ -285,15 +353,56 @@ export interface StageStats {
285
353
  output_count: number;
286
354
  execution_time_ms: number;
287
355
  }
356
+ /**
357
+ * Reference a call-time function parameter inside a stored-function stage
358
+ * body (Insert.record, Update.updates, UpdateById.updates,
359
+ * FindOneAndUpdate.updates, BatchInsert.records, or any nested JSON value).
360
+ *
361
+ * Returns the structural placeholder `{"type": "Parameter", "name": "<name>"}`.
362
+ * ekoDB's `resolve_json_parameters` recognizes this shape and substitutes the
363
+ * actual parameter value at execution time, preserving the original FieldType
364
+ * (Binary, DateTime, UUID, Decimal, Duration, Number, Set, Vector) via the
365
+ * `{type,value}` wrapped form. Safe to use for any type.
366
+ *
367
+ * This is the structural alternative to the text-level `"{{name}}"` form;
368
+ * both are accepted but structural placeholders are preferred when the
369
+ * parameter is a whole-object Record or a value whose type would be lost in
370
+ * raw JSON.
371
+ *
372
+ * @example
373
+ * ```ts
374
+ * const createUser: UserFunction = {
375
+ * label: "users_create",
376
+ * name: "Create user",
377
+ * parameters: {
378
+ * record: { required: true },
379
+ * },
380
+ * functions: [
381
+ * Stage.insert("users", Stage.param("record")),
382
+ * ],
383
+ * };
384
+ * ```
385
+ */
386
+ export interface ParameterRef {
387
+ type: "Parameter";
388
+ name: string;
389
+ }
390
+ export declare function parameterRef(name: string): ParameterRef;
288
391
  export declare const Stage: {
392
+ /**
393
+ * Shorthand for `parameterRef(name)` — builds the structural placeholder
394
+ * `{"type": "Parameter", "name": name}`. See `parameterRef` for the full
395
+ * explanation and example.
396
+ */
397
+ param: (name: string) => ParameterRef;
289
398
  findAll: (collection: string) => FunctionStageConfig;
290
399
  query: (collection: string, filter?: Record<string, any>, sort?: SortFieldConfig[], limit?: number, skip?: number) => FunctionStageConfig;
291
400
  project: (fields: string[], exclude?: boolean) => FunctionStageConfig;
292
401
  group: (by_fields: string[], functions: GroupFunctionConfig[]) => FunctionStageConfig;
293
402
  count: (output_field?: string) => FunctionStageConfig;
294
- insert: (collection: string, record: Record<string, any>, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
295
- update: (collection: string, filter: Record<string, any>, updates: Record<string, any>, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
296
- updateById: (collection: string, record_id: string, updates: Record<string, any>, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
403
+ insert: (collection: string, record: Record<string, any> | ParameterRef, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
404
+ update: (collection: string, filter: Record<string, any>, updates: Record<string, any> | ParameterRef, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
405
+ updateById: (collection: string, record_id: string, updates: Record<string, any> | ParameterRef, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
297
406
  delete: (collection: string, filter: Record<string, any>, bypassRipple?: boolean) => FunctionStageConfig;
298
407
  deleteById: (collection: string, record_id: string, bypassRipple?: boolean) => FunctionStageConfig;
299
408
  batchInsert: (collection: string, records: Record<string, any>[], bypassRipple?: boolean) => FunctionStageConfig;
@@ -314,10 +423,10 @@ export declare const Stage: {
314
423
  embed: (input_field: string, output_field: string, model?: string) => FunctionStageConfig;
315
424
  findById: (collection: string, record_id: string) => FunctionStageConfig;
316
425
  findOne: (collection: string, key: string, value: any) => FunctionStageConfig;
317
- if: (condition: ScriptCondition, thenFunctions: FunctionStageConfig[], elseFunctions?: FunctionStageConfig[]) => FunctionStageConfig;
426
+ if: (condition: FunctionCondition, thenFunctions: FunctionStageConfig[], elseFunctions?: FunctionStageConfig[]) => FunctionStageConfig;
318
427
  forEach: (functions: FunctionStageConfig[]) => FunctionStageConfig;
319
428
  callFunction: (function_label: string, params?: Record<string, any>) => FunctionStageConfig;
320
- findOneAndUpdate: (collection: string, record_id: string, updates: Record<string, any>, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
429
+ findOneAndUpdate: (collection: string, record_id: string, updates: Record<string, any> | ParameterRef, bypassRipple?: boolean, ttl?: number) => FunctionStageConfig;
321
430
  updateWithAction: (collection: string, record_id: string, action: string, field: string, value: any, bypassRipple?: boolean) => FunctionStageConfig;
322
431
  createSavepoint: (name: string) => FunctionStageConfig;
323
432
  rollbackToSavepoint: (name: string) => FunctionStageConfig;
@@ -342,4 +451,75 @@ export declare const Stage: {
342
451
  * @param collection - Optional collection for audit trail storage
343
452
  */
344
453
  swr: (cache_key: string, ttl: string | number, url: string, method?: string, headers?: Record<string, string>, body?: any, timeout_seconds?: number, output_field?: string, collection?: string) => FunctionStageConfig;
454
+ /**
455
+ * Bcrypt-hash a plaintext value and write the result into every record
456
+ * in the working data as `output_field`. Requires ekoDB >= 0.41.0.
457
+ *
458
+ * @param plain - Plaintext to hash. Typically a `"{{password}}"`
459
+ * placeholder that the substituter replaces with the call-time param
460
+ * before this stage runs.
461
+ * @param output_field - Field name to write the bcrypt hash into.
462
+ * @param cost - bcrypt cost factor (4..=31). Defaults to 12 when undefined.
463
+ */
464
+ bcryptHash: (plain: string, output_field: string, cost?: number) => FunctionStageConfig;
465
+ /**
466
+ * Verify a plaintext against a bcrypt hash stored on the first record in
467
+ * the working data. Writes a boolean into `output_field` on every
468
+ * working record. Pair with `Stage.if` to branch on success / failure.
469
+ * Requires ekoDB >= 0.41.0.
470
+ *
471
+ * @param plain - Plaintext to verify (typically `"{{password}}"`).
472
+ * @param hash_field - Name of the field on the current record that
473
+ * holds the stored bcrypt hash (e.g. `"password_hash"`).
474
+ * @param output_field - Field name to write the boolean result into.
475
+ */
476
+ bcryptVerify: (plain: string, hash_field: string, output_field: string) => FunctionStageConfig;
477
+ /**
478
+ * Generate a cryptographically-random token and add it to every record
479
+ * in the working data. Requires ekoDB >= 0.41.0.
480
+ *
481
+ * @param bytes - Number of random bytes to draw (1..=1024).
482
+ * @param output_field - Field name to write the encoded token into.
483
+ * @param encoding - `"hex"` (default) | `"base64"` | `"base64url"`.
484
+ */
485
+ randomToken: (bytes: number, output_field: string, encoding?: "hex" | "base64" | "base64url") => FunctionStageConfig;
486
+ /**
487
+ * Try/Catch error handling for graceful failure recovery.
488
+ * Executes tryFunctions, and if any fail, executes catchFunctions.
489
+ *
490
+ * @param tryFunctions - Functions to attempt.
491
+ * @param catchFunctions - Functions to execute on failure.
492
+ * @param outputErrorField - Field name to store error details (default: "error").
493
+ */
494
+ tryCatch: (tryFunctions: FunctionStageConfig[], catchFunctions: FunctionStageConfig[], outputErrorField?: string) => FunctionStageConfig;
495
+ /**
496
+ * Execute multiple functions in parallel (concurrently).
497
+ * All functions run simultaneously, results are merged.
498
+ *
499
+ * @param functions - Functions to execute concurrently.
500
+ * @param waitForAll - true = wait for all to complete, false = return on first completion.
501
+ */
502
+ parallel: (functions: FunctionStageConfig[], waitForAll?: boolean) => FunctionStageConfig;
503
+ /**
504
+ * Sleep/delay execution for rate limiting or timing control.
505
+ *
506
+ * @param durationMs - Duration in milliseconds: `1000` or `"{{delay_param}}"`.
507
+ */
508
+ sleep: (durationMs: string | number) => FunctionStageConfig;
509
+ /**
510
+ * Return a shaped response (final output formatting).
511
+ * Constructs the final response object from current execution context.
512
+ *
513
+ * @param fields - Fields to include in response with `{{param}}` substitution.
514
+ * @param statusCode - HTTP status code (default: 200).
515
+ */
516
+ returnResponse: (fields: Record<string, any>, statusCode?: number) => FunctionStageConfig;
517
+ /**
518
+ * Validate data against a JSON schema before processing.
519
+ *
520
+ * @param schema - JSON Schema to validate against.
521
+ * @param dataField - Field containing data to validate.
522
+ * @param onError - Functions to execute on validation failure.
523
+ */
524
+ validate: (schema: Record<string, any>, dataField: string, onError?: FunctionStageConfig[]) => FunctionStageConfig;
345
525
  };
package/dist/functions.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  /**
3
- * Scripts API for ekoDB TypeScript client
3
+ * Functions API for ekoDB TypeScript client
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Stage = exports.ChatMessage = void 0;
7
+ exports.parameterRef = parameterRef;
7
8
  exports.ChatMessage = {
8
9
  system: (content) => ({
9
10
  role: "system",
@@ -18,8 +19,17 @@ exports.ChatMessage = {
18
19
  content: content,
19
20
  }),
20
21
  };
22
+ function parameterRef(name) {
23
+ return { type: "Parameter", name };
24
+ }
21
25
  // Stage builder functions
22
26
  exports.Stage = {
27
+ /**
28
+ * Shorthand for `parameterRef(name)` — builds the structural placeholder
29
+ * `{"type": "Parameter", "name": name}`. See `parameterRef` for the full
30
+ * explanation and example.
31
+ */
32
+ param: (name) => parameterRef(name),
23
33
  findAll: (collection) => ({
24
34
  type: "FindAll",
25
35
  collection,
@@ -258,4 +268,111 @@ exports.Stage = {
258
268
  output_field,
259
269
  collection,
260
270
  }),
271
+ /**
272
+ * Bcrypt-hash a plaintext value and write the result into every record
273
+ * in the working data as `output_field`. Requires ekoDB >= 0.41.0.
274
+ *
275
+ * @param plain - Plaintext to hash. Typically a `"{{password}}"`
276
+ * placeholder that the substituter replaces with the call-time param
277
+ * before this stage runs.
278
+ * @param output_field - Field name to write the bcrypt hash into.
279
+ * @param cost - bcrypt cost factor (4..=31). Defaults to 12 when undefined.
280
+ */
281
+ bcryptHash: (plain, output_field, cost) => ({
282
+ type: "BcryptHash",
283
+ plain,
284
+ cost,
285
+ output_field,
286
+ }),
287
+ /**
288
+ * Verify a plaintext against a bcrypt hash stored on the first record in
289
+ * the working data. Writes a boolean into `output_field` on every
290
+ * working record. Pair with `Stage.if` to branch on success / failure.
291
+ * Requires ekoDB >= 0.41.0.
292
+ *
293
+ * @param plain - Plaintext to verify (typically `"{{password}}"`).
294
+ * @param hash_field - Name of the field on the current record that
295
+ * holds the stored bcrypt hash (e.g. `"password_hash"`).
296
+ * @param output_field - Field name to write the boolean result into.
297
+ */
298
+ bcryptVerify: (plain, hash_field, output_field) => ({
299
+ type: "BcryptVerify",
300
+ plain,
301
+ hash_field,
302
+ output_field,
303
+ }),
304
+ /**
305
+ * Generate a cryptographically-random token and add it to every record
306
+ * in the working data. Requires ekoDB >= 0.41.0.
307
+ *
308
+ * @param bytes - Number of random bytes to draw (1..=1024).
309
+ * @param output_field - Field name to write the encoded token into.
310
+ * @param encoding - `"hex"` (default) | `"base64"` | `"base64url"`.
311
+ */
312
+ randomToken: (bytes, output_field, encoding) => ({
313
+ type: "RandomToken",
314
+ bytes,
315
+ encoding,
316
+ output_field,
317
+ }),
318
+ /**
319
+ * Try/Catch error handling for graceful failure recovery.
320
+ * Executes tryFunctions, and if any fail, executes catchFunctions.
321
+ *
322
+ * @param tryFunctions - Functions to attempt.
323
+ * @param catchFunctions - Functions to execute on failure.
324
+ * @param outputErrorField - Field name to store error details (default: "error").
325
+ */
326
+ tryCatch: (tryFunctions, catchFunctions, outputErrorField) => ({
327
+ type: "TryCatch",
328
+ try_functions: tryFunctions,
329
+ catch_functions: catchFunctions,
330
+ output_error_field: outputErrorField,
331
+ }),
332
+ /**
333
+ * Execute multiple functions in parallel (concurrently).
334
+ * All functions run simultaneously, results are merged.
335
+ *
336
+ * @param functions - Functions to execute concurrently.
337
+ * @param waitForAll - true = wait for all to complete, false = return on first completion.
338
+ */
339
+ parallel: (functions, waitForAll = true) => ({
340
+ type: "Parallel",
341
+ functions,
342
+ wait_for_all: waitForAll,
343
+ }),
344
+ /**
345
+ * Sleep/delay execution for rate limiting or timing control.
346
+ *
347
+ * @param durationMs - Duration in milliseconds: `1000` or `"{{delay_param}}"`.
348
+ */
349
+ sleep: (durationMs) => ({
350
+ type: "Sleep",
351
+ duration_ms: durationMs,
352
+ }),
353
+ /**
354
+ * Return a shaped response (final output formatting).
355
+ * Constructs the final response object from current execution context.
356
+ *
357
+ * @param fields - Fields to include in response with `{{param}}` substitution.
358
+ * @param statusCode - HTTP status code (default: 200).
359
+ */
360
+ returnResponse: (fields, statusCode) => ({
361
+ type: "Return",
362
+ fields,
363
+ status_code: statusCode,
364
+ }),
365
+ /**
366
+ * Validate data against a JSON schema before processing.
367
+ *
368
+ * @param schema - JSON Schema to validate against.
369
+ * @param dataField - Field containing data to validate.
370
+ * @param onError - Functions to execute on validation failure.
371
+ */
372
+ validate: (schema, dataField, onError) => ({
373
+ type: "Validate",
374
+ schema,
375
+ data_field: dataField,
376
+ on_error: onError,
377
+ }),
261
378
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Unit tests for the stored-function builder helpers (Stage + parameterRef).
3
+ *
4
+ * These tests cover the pure-data construction helpers and the structural
5
+ * parameter placeholder. They don't hit a running ekoDB — server-side
6
+ * behavior is covered by the Rust integration tests in
7
+ * `ekodb/ekodb_server/tests/function_parameters_tests.rs`.
8
+ */
9
+ export {};