@ekodb/ekodb-client 0.17.0 → 0.18.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.
@@ -15,6 +15,19 @@ export interface UserFunction {
15
15
  tags?: string[];
16
16
  created_at?: string;
17
17
  updated_at?: string;
18
+ /**
19
+ * REST method this function answers — `"GET"`, `"POST"`, etc.
20
+ * Pair with `http_path` to expose the function under the
21
+ * path-routed dispatcher at `/api/route/{path}`.
22
+ * Requires ekoDB >= 0.42.0.
23
+ */
24
+ http_method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
25
+ /**
26
+ * REST path pattern (e.g. `"/users/:id"`). Path segments
27
+ * starting with `:` are extracted into the function's params
28
+ * map at call time. Requires ekoDB >= 0.42.0.
29
+ */
30
+ http_path?: string;
18
31
  }
19
32
  export interface ParameterDefinition {
20
33
  required: boolean;
@@ -235,6 +248,167 @@ export type FunctionStageConfig = {
235
248
  bytes: number;
236
249
  encoding?: "hex" | "base64" | "base64url";
237
250
  output_field: string;
251
+ } | {
252
+ /**
253
+ * Sign a JWT and write the resulting token to every working
254
+ * record. Pair with `BcryptVerify` to issue a session token
255
+ * after login. Use `"{{env.JWT_SECRET}}"` for `secret` so the
256
+ * LLM never sees the operator-owned signing key. `iat` and
257
+ * `exp` are auto-stamped when `expires_in_secs` is set.
258
+ * Requires ekoDB >= 0.42.0.
259
+ */
260
+ type: "JwtSign";
261
+ claims: Record<string, unknown>;
262
+ secret: string;
263
+ algorithm?: "HS256" | "HS384" | "HS512";
264
+ expires_in_secs?: number;
265
+ output_field: string;
266
+ } | {
267
+ /**
268
+ * Verify a JWT held in `token_field` on the first working
269
+ * record. On success, writes the decoded claims object into
270
+ * `output_field`. On failure, writes `null` so callers can
271
+ * branch with `If { FieldEquals { value: null } }` to reject.
272
+ * Requires ekoDB >= 0.42.0.
273
+ */
274
+ type: "JwtVerify";
275
+ token_field: string;
276
+ secret: string;
277
+ algorithm?: "HS256" | "HS384" | "HS512";
278
+ output_field: string;
279
+ } | {
280
+ /**
281
+ * Send a transactional email through a provider's REST API.
282
+ * Today only `provider = "sendgrid"` is supported. Pull the
283
+ * API key from `"{{env.SENDGRID_API_KEY}}"` so the LLM never
284
+ * sees the operator-owned secret. Result envelope
285
+ * `{provider_status, provider_message, provider}` is written
286
+ * to `output_field` (defaults to `"email_send"`).
287
+ * Requires ekoDB >= 0.42.0.
288
+ */
289
+ type: "EmailSend";
290
+ to: string;
291
+ subject: string;
292
+ body: string;
293
+ from: string;
294
+ reply_to?: string;
295
+ api_key: string;
296
+ provider?: "sendgrid";
297
+ html?: boolean;
298
+ output_field?: string;
299
+ } | {
300
+ /** HMAC-SHA256/384/512 sign. Requires ekoDB >= 0.42.0. */
301
+ type: "HmacSign";
302
+ input: string;
303
+ secret: string;
304
+ algorithm?: "sha256" | "sha384" | "sha512";
305
+ output_field: string;
306
+ encoding?: "hex" | "base64";
307
+ } | {
308
+ /** HMAC verify (constant-time). Writes a boolean. */
309
+ type: "HmacVerify";
310
+ input: string;
311
+ provided_mac: string;
312
+ secret: string;
313
+ algorithm?: "sha256" | "sha384" | "sha512";
314
+ encoding?: "hex" | "base64";
315
+ output_field: string;
316
+ } | {
317
+ /** AES-256-GCM authenticated encryption. */
318
+ type: "AesEncrypt";
319
+ plaintext: string;
320
+ key: string;
321
+ key_encoding?: "hex" | "base64" | "base64url";
322
+ output_field: string;
323
+ } | {
324
+ /** AES-256-GCM decrypt. Reads `{ciphertext, nonce}` envelope from `ciphertext_field`. */
325
+ type: "AesDecrypt";
326
+ ciphertext_field: string;
327
+ key: string;
328
+ key_encoding?: "hex" | "base64" | "base64url";
329
+ output_field: string;
330
+ } | {
331
+ /** Generate a v4 UUID into `output_field`. */
332
+ type: "UuidGenerate";
333
+ output_field: string;
334
+ } | {
335
+ /** TOTP code generation (RFC 6238). */
336
+ type: "TotpGenerate";
337
+ secret: string;
338
+ digits?: 6 | 8;
339
+ period?: number;
340
+ algorithm?: "sha1" | "sha256" | "sha512";
341
+ output_field: string;
342
+ } | {
343
+ /** TOTP verify; tolerates `skew` time-steps either side. */
344
+ type: "TotpVerify";
345
+ code: string;
346
+ secret: string;
347
+ digits?: 6 | 8;
348
+ period?: number;
349
+ algorithm?: "sha1" | "sha256" | "sha512";
350
+ skew?: number;
351
+ output_field: string;
352
+ } | {
353
+ /** Base64 encode (`url_safe = true` for URL-safe / no-pad). */
354
+ type: "Base64Encode";
355
+ input: string;
356
+ url_safe?: boolean;
357
+ output_field: string;
358
+ } | {
359
+ /** Base64 decode → UTF-8 string. Fail-closed. */
360
+ type: "Base64Decode";
361
+ input: string;
362
+ url_safe?: boolean;
363
+ output_field: string;
364
+ } | {
365
+ /** Hex encode (lowercase). */
366
+ type: "HexEncode";
367
+ input: string;
368
+ output_field: string;
369
+ } | {
370
+ /** Hex decode → UTF-8 string. Fail-closed. */
371
+ type: "HexDecode";
372
+ input: string;
373
+ output_field: string;
374
+ } | {
375
+ /** URL-friendly slug. */
376
+ type: "Slugify";
377
+ input: string;
378
+ output_field: string;
379
+ } | {
380
+ /**
381
+ * Idempotency-key claim (KV SETNX with TTL). Writes
382
+ * `{claimed: true, key}` on first call, `{claimed: false, key,
383
+ * response}` on replay. Requires ekoDB >= 0.42.0.
384
+ */
385
+ type: "IdempotencyClaim";
386
+ key: string;
387
+ ttl_secs: number;
388
+ output_field: string;
389
+ } | {
390
+ /**
391
+ * Fixed-window rate-limit gate. `on_exceed` either errors
392
+ * (`"fail"`, default) or writes `allowed: false` (`"skip"`).
393
+ */
394
+ type: "RateLimit";
395
+ key: string;
396
+ limit: number;
397
+ window_secs: number;
398
+ on_exceed?: "fail" | "skip";
399
+ output_field: string;
400
+ } | {
401
+ /** Distributed-lock acquire (token-fenced). */
402
+ type: "LockAcquire";
403
+ key: string;
404
+ ttl_secs: number;
405
+ output_field: string;
406
+ } | {
407
+ /** Distributed-lock release; token-fenced (no foreign release). */
408
+ type: "LockRelease";
409
+ key: string;
410
+ token: string;
411
+ output_field: string;
238
412
  } | {
239
413
  /**
240
414
  * Try/Catch error handling for graceful failure recovery.
@@ -483,6 +657,48 @@ export declare const Stage: {
483
657
  * @param encoding - `"hex"` (default) | `"base64"` | `"base64url"`.
484
658
  */
485
659
  randomToken: (bytes: number, output_field: string, encoding?: "hex" | "base64" | "base64url") => FunctionStageConfig;
660
+ /**
661
+ * Sign a JWT and write the resulting token to every working
662
+ * record. Pair with `Stage.bcryptVerify` to issue a session
663
+ * token after login. Use `"{{env.JWT_SECRET}}"` for `secret` so
664
+ * the LLM never sees the operator-owned signing key. `iat` and
665
+ * `exp` are auto-stamped when `expires_in_secs` is set.
666
+ * Requires ekoDB >= 0.42.0.
667
+ *
668
+ * @param claims - JWT payload claims.
669
+ * @param secret - Signing secret (typically `"{{env.JWT_SECRET}}"`).
670
+ * @param output_field - Field name to write the signed JWT into.
671
+ * @param expires_in_secs - Lifetime in seconds (auto-stamps `iat` + `exp`).
672
+ * @param algorithm - `"HS256"` (default) | `"HS384"` | `"HS512"`.
673
+ */
674
+ jwtSign: (claims: Record<string, unknown>, secret: string, output_field: string, expires_in_secs?: number, algorithm?: "HS256" | "HS384" | "HS512") => FunctionStageConfig;
675
+ /**
676
+ * Verify a JWT held in `token_field` on the first working record.
677
+ * On success writes the decoded claims object into `output_field`;
678
+ * on failure writes `null`. Branch with `Stage.if` matching
679
+ * `output_field == null` to reject. Requires ekoDB >= 0.42.0.
680
+ *
681
+ * @param token_field - Field on the working record holding the JWT.
682
+ * @param secret - Verification secret (must match the signing secret).
683
+ * @param output_field - Field name to write decoded claims into.
684
+ * @param algorithm - Expected algorithm (default `"HS256"`).
685
+ */
686
+ jwtVerify: (token_field: string, secret: string, output_field: string, algorithm?: "HS256" | "HS384" | "HS512") => FunctionStageConfig;
687
+ /**
688
+ * Send a transactional email. Today only the `"sendgrid"`
689
+ * provider is supported. Use `"{{env.SENDGRID_API_KEY}}"` for
690
+ * `api_key` so the LLM never sees the operator-owned secret.
691
+ * Set `html: true` to send `text/html`. The result envelope
692
+ * (`{provider_status, provider_message, provider}`) is written
693
+ * to `output_field` (default `"email_send"`).
694
+ * Requires ekoDB >= 0.42.0.
695
+ */
696
+ emailSend: (to: string, subject: string, body: string, from: string, api_key: string, options?: {
697
+ reply_to?: string;
698
+ provider?: "sendgrid";
699
+ html?: boolean;
700
+ output_field?: string;
701
+ }) => FunctionStageConfig;
486
702
  /**
487
703
  * Try/Catch error handling for graceful failure recovery.
488
704
  * Executes tryFunctions, and if any fail, executes catchFunctions.
@@ -522,4 +738,63 @@ export declare const Stage: {
522
738
  * @param onError - Functions to execute on validation failure.
523
739
  */
524
740
  validate: (schema: Record<string, any>, dataField: string, onError?: FunctionStageConfig[]) => FunctionStageConfig;
741
+ /**
742
+ * HMAC-SHA256/384/512 sign. Use for outbound webhook signing or
743
+ * pre-signed URL generation. Requires ekoDB >= 0.42.0.
744
+ */
745
+ hmacSign: (input: string, secret: string, output_field: string, options?: {
746
+ algorithm?: "sha256" | "sha384" | "sha512";
747
+ encoding?: "hex" | "base64";
748
+ }) => FunctionStageConfig;
749
+ /** HMAC verify (constant-time). Writes a boolean. */
750
+ hmacVerify: (input: string, provided_mac: string, secret: string, output_field: string, options?: {
751
+ algorithm?: "sha256" | "sha384" | "sha512";
752
+ encoding?: "hex" | "base64";
753
+ }) => FunctionStageConfig;
754
+ /** AES-256-GCM encrypt; writes `{ciphertext, nonce}` envelope. */
755
+ aesEncrypt: (plaintext: string, key: string, output_field: string, key_encoding?: "hex" | "base64" | "base64url") => FunctionStageConfig;
756
+ /** AES-256-GCM decrypt; reads envelope from `ciphertext_field`. */
757
+ aesDecrypt: (ciphertext_field: string, key: string, output_field: string, key_encoding?: "hex" | "base64" | "base64url") => FunctionStageConfig;
758
+ /** Generate a v4 UUID into `output_field`. */
759
+ uuidGenerate: (output_field: string) => FunctionStageConfig;
760
+ /** TOTP code generation (RFC 6238). */
761
+ totpGenerate: (secret: string, output_field: string, options?: {
762
+ digits?: 6 | 8;
763
+ period?: number;
764
+ algorithm?: "sha1" | "sha256" | "sha512";
765
+ }) => FunctionStageConfig;
766
+ /** TOTP verify; tolerates `skew` time-steps either side (default 1). */
767
+ totpVerify: (code: string, secret: string, output_field: string, options?: {
768
+ digits?: 6 | 8;
769
+ period?: number;
770
+ algorithm?: "sha1" | "sha256" | "sha512";
771
+ skew?: number;
772
+ }) => FunctionStageConfig;
773
+ /** Base64 encode (`url_safe = true` for URL-safe / no-pad). */
774
+ base64Encode: (input: string, output_field: string, url_safe?: boolean) => FunctionStageConfig;
775
+ /** Base64 decode → UTF-8 string. Fail-closed. */
776
+ base64Decode: (input: string, output_field: string, url_safe?: boolean) => FunctionStageConfig;
777
+ /** Hex encode (lowercase). */
778
+ hexEncode: (input: string, output_field: string) => FunctionStageConfig;
779
+ /** Hex decode → UTF-8 string. Fail-closed. */
780
+ hexDecode: (input: string, output_field: string) => FunctionStageConfig;
781
+ /** URL-friendly slug. */
782
+ slugify: (input: string, output_field: string) => FunctionStageConfig;
783
+ /**
784
+ * Idempotency-key claim (KV SETNX with TTL). Pass an idempotency
785
+ * key (typically `"{{idempotency_key}}"`) and a TTL; first call
786
+ * writes `{claimed: true, key}`, subsequent calls within the TTL
787
+ * write `{claimed: false, key, response}` so the caller can
788
+ * short-circuit. Requires ekoDB >= 0.42.0.
789
+ */
790
+ idempotencyClaim: (key: string, ttl_secs: number, output_field: string) => FunctionStageConfig;
791
+ /**
792
+ * Fixed-window rate-limit gate. `on_exceed` either errors
793
+ * (`"fail"`, default) or writes `allowed: false` (`"skip"`).
794
+ */
795
+ rateLimit: (key: string, limit: number, window_secs: number, output_field: string, on_exceed?: "fail" | "skip") => FunctionStageConfig;
796
+ /** Distributed-lock acquire (token-fenced). */
797
+ lockAcquire: (key: string, ttl_secs: number, output_field: string) => FunctionStageConfig;
798
+ /** Distributed-lock release; only releases on token match. */
799
+ lockRelease: (key: string, token: string, output_field: string) => FunctionStageConfig;
525
800
  };
package/dist/functions.js CHANGED
@@ -315,6 +315,67 @@ exports.Stage = {
315
315
  encoding,
316
316
  output_field,
317
317
  }),
318
+ /**
319
+ * Sign a JWT and write the resulting token to every working
320
+ * record. Pair with `Stage.bcryptVerify` to issue a session
321
+ * token after login. Use `"{{env.JWT_SECRET}}"` for `secret` so
322
+ * the LLM never sees the operator-owned signing key. `iat` and
323
+ * `exp` are auto-stamped when `expires_in_secs` is set.
324
+ * Requires ekoDB >= 0.42.0.
325
+ *
326
+ * @param claims - JWT payload claims.
327
+ * @param secret - Signing secret (typically `"{{env.JWT_SECRET}}"`).
328
+ * @param output_field - Field name to write the signed JWT into.
329
+ * @param expires_in_secs - Lifetime in seconds (auto-stamps `iat` + `exp`).
330
+ * @param algorithm - `"HS256"` (default) | `"HS384"` | `"HS512"`.
331
+ */
332
+ jwtSign: (claims, secret, output_field, expires_in_secs, algorithm) => ({
333
+ type: "JwtSign",
334
+ claims,
335
+ secret,
336
+ algorithm,
337
+ expires_in_secs,
338
+ output_field,
339
+ }),
340
+ /**
341
+ * Verify a JWT held in `token_field` on the first working record.
342
+ * On success writes the decoded claims object into `output_field`;
343
+ * on failure writes `null`. Branch with `Stage.if` matching
344
+ * `output_field == null` to reject. Requires ekoDB >= 0.42.0.
345
+ *
346
+ * @param token_field - Field on the working record holding the JWT.
347
+ * @param secret - Verification secret (must match the signing secret).
348
+ * @param output_field - Field name to write decoded claims into.
349
+ * @param algorithm - Expected algorithm (default `"HS256"`).
350
+ */
351
+ jwtVerify: (token_field, secret, output_field, algorithm) => ({
352
+ type: "JwtVerify",
353
+ token_field,
354
+ secret,
355
+ algorithm,
356
+ output_field,
357
+ }),
358
+ /**
359
+ * Send a transactional email. Today only the `"sendgrid"`
360
+ * provider is supported. Use `"{{env.SENDGRID_API_KEY}}"` for
361
+ * `api_key` so the LLM never sees the operator-owned secret.
362
+ * Set `html: true` to send `text/html`. The result envelope
363
+ * (`{provider_status, provider_message, provider}`) is written
364
+ * to `output_field` (default `"email_send"`).
365
+ * Requires ekoDB >= 0.42.0.
366
+ */
367
+ emailSend: (to, subject, body, from, api_key, options) => ({
368
+ type: "EmailSend",
369
+ to,
370
+ subject,
371
+ body,
372
+ from,
373
+ reply_to: options?.reply_to,
374
+ api_key,
375
+ provider: options?.provider,
376
+ html: options?.html,
377
+ output_field: options?.output_field,
378
+ }),
318
379
  /**
319
380
  * Try/Catch error handling for graceful failure recovery.
320
381
  * Executes tryFunctions, and if any fail, executes catchFunctions.
@@ -375,4 +436,138 @@ exports.Stage = {
375
436
  data_field: dataField,
376
437
  on_error: onError,
377
438
  }),
439
+ /**
440
+ * HMAC-SHA256/384/512 sign. Use for outbound webhook signing or
441
+ * pre-signed URL generation. Requires ekoDB >= 0.42.0.
442
+ */
443
+ hmacSign: (input, secret, output_field, options) => ({
444
+ type: "HmacSign",
445
+ input,
446
+ secret,
447
+ algorithm: options?.algorithm,
448
+ output_field,
449
+ encoding: options?.encoding,
450
+ }),
451
+ /** HMAC verify (constant-time). Writes a boolean. */
452
+ hmacVerify: (input, provided_mac, secret, output_field, options) => ({
453
+ type: "HmacVerify",
454
+ input,
455
+ provided_mac,
456
+ secret,
457
+ algorithm: options?.algorithm,
458
+ encoding: options?.encoding,
459
+ output_field,
460
+ }),
461
+ /** AES-256-GCM encrypt; writes `{ciphertext, nonce}` envelope. */
462
+ aesEncrypt: (plaintext, key, output_field, key_encoding) => ({
463
+ type: "AesEncrypt",
464
+ plaintext,
465
+ key,
466
+ key_encoding,
467
+ output_field,
468
+ }),
469
+ /** AES-256-GCM decrypt; reads envelope from `ciphertext_field`. */
470
+ aesDecrypt: (ciphertext_field, key, output_field, key_encoding) => ({
471
+ type: "AesDecrypt",
472
+ ciphertext_field,
473
+ key,
474
+ key_encoding,
475
+ output_field,
476
+ }),
477
+ /** Generate a v4 UUID into `output_field`. */
478
+ uuidGenerate: (output_field) => ({
479
+ type: "UuidGenerate",
480
+ output_field,
481
+ }),
482
+ /** TOTP code generation (RFC 6238). */
483
+ totpGenerate: (secret, output_field, options) => ({
484
+ type: "TotpGenerate",
485
+ secret,
486
+ digits: options?.digits,
487
+ period: options?.period,
488
+ algorithm: options?.algorithm,
489
+ output_field,
490
+ }),
491
+ /** TOTP verify; tolerates `skew` time-steps either side (default 1). */
492
+ totpVerify: (code, secret, output_field, options) => ({
493
+ type: "TotpVerify",
494
+ code,
495
+ secret,
496
+ digits: options?.digits,
497
+ period: options?.period,
498
+ algorithm: options?.algorithm,
499
+ skew: options?.skew,
500
+ output_field,
501
+ }),
502
+ /** Base64 encode (`url_safe = true` for URL-safe / no-pad). */
503
+ base64Encode: (input, output_field, url_safe) => ({
504
+ type: "Base64Encode",
505
+ input,
506
+ url_safe,
507
+ output_field,
508
+ }),
509
+ /** Base64 decode → UTF-8 string. Fail-closed. */
510
+ base64Decode: (input, output_field, url_safe) => ({
511
+ type: "Base64Decode",
512
+ input,
513
+ url_safe,
514
+ output_field,
515
+ }),
516
+ /** Hex encode (lowercase). */
517
+ hexEncode: (input, output_field) => ({
518
+ type: "HexEncode",
519
+ input,
520
+ output_field,
521
+ }),
522
+ /** Hex decode → UTF-8 string. Fail-closed. */
523
+ hexDecode: (input, output_field) => ({
524
+ type: "HexDecode",
525
+ input,
526
+ output_field,
527
+ }),
528
+ /** URL-friendly slug. */
529
+ slugify: (input, output_field) => ({
530
+ type: "Slugify",
531
+ input,
532
+ output_field,
533
+ }),
534
+ /**
535
+ * Idempotency-key claim (KV SETNX with TTL). Pass an idempotency
536
+ * key (typically `"{{idempotency_key}}"`) and a TTL; first call
537
+ * writes `{claimed: true, key}`, subsequent calls within the TTL
538
+ * write `{claimed: false, key, response}` so the caller can
539
+ * short-circuit. Requires ekoDB >= 0.42.0.
540
+ */
541
+ idempotencyClaim: (key, ttl_secs, output_field) => ({
542
+ type: "IdempotencyClaim",
543
+ key,
544
+ ttl_secs,
545
+ output_field,
546
+ }),
547
+ /**
548
+ * Fixed-window rate-limit gate. `on_exceed` either errors
549
+ * (`"fail"`, default) or writes `allowed: false` (`"skip"`).
550
+ */
551
+ rateLimit: (key, limit, window_secs, output_field, on_exceed) => ({
552
+ type: "RateLimit",
553
+ key,
554
+ limit,
555
+ window_secs,
556
+ on_exceed,
557
+ output_field,
558
+ }),
559
+ /** Distributed-lock acquire (token-fenced). */
560
+ lockAcquire: (key, ttl_secs, output_field) => ({
561
+ type: "LockAcquire",
562
+ key,
563
+ ttl_secs,
564
+ output_field,
565
+ }),
566
+ /** Distributed-lock release; only releases on token match. */
567
+ lockRelease: (key, token, output_field) => ({
568
+ type: "LockRelease",
569
+ key,
570
+ token,
571
+ output_field,
572
+ }),
378
573
  };