@ekodb/ekodb-client 0.17.0 → 0.18.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.
- package/dist/functions.d.ts +275 -0
- package/dist/functions.js +195 -0
- package/dist/functions.test.js +215 -0
- package/package.json +1 -1
- package/src/functions.test.ts +282 -0
- package/src/functions.ts +501 -0
package/dist/functions.d.ts
CHANGED
|
@@ -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
|
};
|