upstash-lua 0.3.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/README.md ADDED
@@ -0,0 +1,319 @@
1
+ ![Hero](https://raw.githubusercontent.com/strandhvilliam/upstash-lua/main/assets/upstash-lua-hero.jpg)
2
+
3
+ Type-safe Lua scripts for Upstash Redis with StandardSchemaV1 validation.
4
+
5
+ ## Features
6
+
7
+ - **Full TypeScript inference** for keys, args, and return values
8
+ - **Type-safe Lua templates** - Use `${KEYS.name}` and `${ARGV.name}` with autocomplete and compile-time errors
9
+ - **Input validation** using StandardSchemaV1 schemas (Zod, Effect Schema, ArkType, etc.)
10
+ - **Efficient execution** via EVALSHA with automatic NOSCRIPT fallback
11
+ - **Universal runtime support** - Node.js 18+, Bun, Cloudflare Workers, Vercel Edge
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ bun add upstash-lua @upstash/redis zod
17
+ # or
18
+ npm install upstash-lua @upstash/redis zod
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { z } from "zod"
25
+ import { defineScript, lua } from "upstash-lua"
26
+ import { Redis } from "@upstash/redis"
27
+
28
+ const redis = new Redis({
29
+ url: process.env.UPSTASH_REDIS_REST_URL,
30
+ token: process.env.UPSTASH_REDIS_REST_TOKEN,
31
+ })
32
+
33
+ // Define a rate limiter script with type-safe Lua template
34
+ const rateLimit = defineScript({
35
+ name: "rateLimit",
36
+ keys: {
37
+ key: z.string(),
38
+ },
39
+ args: {
40
+ limit: z.number().int().positive().transform(String),
41
+ windowSeconds: z.number().int().positive().transform(String),
42
+ },
43
+ lua: ({ KEYS, ARGV }) => lua`
44
+ local current = redis.call("INCR", ${KEYS.key})
45
+ if current == 1 then
46
+ redis.call("EXPIRE", ${KEYS.key}, ${ARGV.windowSeconds})
47
+ end
48
+ local allowed = current <= tonumber(${ARGV.limit}) and 1 or 0
49
+ return { allowed, tonumber(${ARGV.limit}) - current }
50
+ `,
51
+ returns: z.tuple([z.number(), z.number()]).transform(([allowed, rem]) => ({
52
+ allowed: allowed === 1,
53
+ remaining: rem,
54
+ })),
55
+ })
56
+
57
+ // Execute with full type safety
58
+ const result = await rateLimit.run(redis, {
59
+ keys: { key: "rl:user:123" },
60
+ args: { limit: 10, windowSeconds: 60 },
61
+ })
62
+
63
+ console.log(result.allowed) // boolean
64
+ console.log(result.remaining) // number
65
+ ```
66
+
67
+ ## API
68
+
69
+ ### `defineScript(options)`
70
+
71
+ Creates a type-safe Lua script definition.
72
+
73
+ #### Options
74
+
75
+ | Property | Type | Description |
76
+ |----------|------|-------------|
77
+ | `name` | `string` | Human-readable name (used in error messages) |
78
+ | `lua` | `string \| LuaFunction` | Lua script source code (string) or type-safe template function |
79
+ | `keys` | `Record<string, Schema>` | Key schemas - order determines KEYS[1], KEYS[2], etc. |
80
+ | `args` | `Record<string, Schema>` | Arg schemas - order determines ARGV[1], ARGV[2], etc. |
81
+ | `returns` | `Schema` | Optional return value schema |
82
+
83
+ **Important:** Key/arg order is determined by object literal insertion order. Always define using object literal syntax in the intended order.
84
+
85
+ #### Lua Property: String vs Function
86
+
87
+ The `lua` property can be either a plain string or a function that returns a `lua` template:
88
+
89
+ **String form** (manual KEYS/ARGV indexing):
90
+ ```typescript
91
+ lua: `return redis.call("GET", KEYS[1])`
92
+ ```
93
+
94
+ **Function form** (type-safe with autocomplete):
95
+ ```typescript
96
+ lua: ({ KEYS, ARGV }) => lua`
97
+ return redis.call("GET", ${KEYS.userKey})
98
+ `
99
+ ```
100
+
101
+ The function form provides:
102
+ - ✅ Autocomplete for `KEYS.*` and `ARGV.*` properties
103
+ - ✅ Compile-time errors for invalid key/arg references
104
+ - ✅ Automatic compilation of `${KEYS.name}` → `KEYS[n]` and `${ARGV.name}` → `ARGV[n]`
105
+
106
+ #### Returns
107
+
108
+ A `Script` object with:
109
+
110
+ - `run(redis, input)` - Execute with full validation
111
+ - `runRaw(redis, input)` - Execute without return validation
112
+ - `name`, `lua`, `keyNames`, `argNames` - Metadata
113
+
114
+ ### Schema Requirements
115
+
116
+ Keys and args must output strings (Redis only accepts strings). Use transforms:
117
+
118
+ ```typescript
119
+ args: {
120
+ // Number input → string output
121
+ limit: z.number().transform(String),
122
+
123
+ // Boolean input → "1" or "0" output
124
+ enabled: z.boolean().transform(b => b ? "1" : "0"),
125
+
126
+ // String input → string output (no transform needed)
127
+ key: z.string(),
128
+ }
129
+ ```
130
+
131
+ ## Examples
132
+
133
+ ### Type-Safe Lua Template
134
+
135
+ Use the `lua` tagged template function for type-safe key and argument references:
136
+
137
+ ```typescript
138
+ import { defineScript, lua } from "upstash-lua"
139
+ import { z } from "zod"
140
+
141
+ const getUser = defineScript({
142
+ name: "getUser",
143
+ keys: {
144
+ userKey: z.string(),
145
+ },
146
+ args: {
147
+ field: z.string(),
148
+ },
149
+ lua: ({ KEYS, ARGV }) => lua`
150
+ -- TypeScript autocomplete works here!
151
+ local key = ${KEYS.userKey}
152
+ local field = ${ARGV.field}
153
+ return redis.call("HGET", key, field)
154
+ `,
155
+ returns: z.string().nullable(),
156
+ })
157
+
158
+ // ${KEYS.userKey} automatically becomes KEYS[1]
159
+ // ${ARGV.field} automatically becomes ARGV[1]
160
+ ```
161
+
162
+ ### Simple Script (No Keys/Args)
163
+
164
+ ```typescript
165
+ const ping = defineScript({
166
+ name: "ping",
167
+ lua: 'return redis.call("PING")',
168
+ returns: z.string(),
169
+ })
170
+
171
+ const result = await ping.run(redis)
172
+ // result: "PONG"
173
+ ```
174
+
175
+ Or with the function form:
176
+
177
+ ```typescript
178
+ const ping = defineScript({
179
+ name: "ping",
180
+ lua: () => lua`return redis.call("PING")`,
181
+ returns: z.string(),
182
+ })
183
+ ```
184
+
185
+ ### Script Without Return Validation
186
+
187
+ ```typescript
188
+ const getData = defineScript({
189
+ name: "getData",
190
+ lua: 'return redis.call("HGETALL", KEYS[1])',
191
+ keys: { key: z.string() },
192
+ // No returns schema - result is unknown
193
+ })
194
+
195
+ const result = await getData.run(redis, { keys: { key: "user:123" } })
196
+ // result: unknown
197
+ ```
198
+
199
+ ### HGETALL with `hashResult()`
200
+
201
+ Redis commands like `HGETALL` return flat arrays of alternating key-value pairs:
202
+ `["field1", "value1", "field2", "value2"]`
203
+
204
+ The `hashResult()` helper converts this to an object before validation, enabling you to use `z.object()`:
205
+
206
+ ```typescript
207
+ import { z } from "zod"
208
+ import { defineScript, hashResult } from "upstash-lua"
209
+
210
+ const getUser = defineScript({
211
+ name: "getUser",
212
+ keys: { key: z.string() },
213
+ lua: 'return redis.call("HGETALL", KEYS[1])',
214
+ returns: hashResult(z.object({
215
+ name: z.string(),
216
+ email: z.string(),
217
+ age: z.coerce.number(),
218
+ is_admin: z.string().transform(v => v === "true"),
219
+ })),
220
+ })
221
+
222
+ const user = await getUser.run(redis, { keys: { key: "user:123" } })
223
+ // user: { name: string, email: string, age: number, is_admin: boolean }
224
+ ```
225
+
226
+ Works with all Zod object features:
227
+
228
+ ```typescript
229
+ // Optional fields
230
+ returns: hashResult(z.object({
231
+ name: z.string(),
232
+ email: z.string().optional(),
233
+ }))
234
+
235
+ // Partial objects
236
+ returns: hashResult(z.object({
237
+ name: z.string(),
238
+ email: z.string(),
239
+ }).partial())
240
+
241
+ // Passthrough for extra fields
242
+ returns: hashResult(z.object({
243
+ name: z.string(),
244
+ }).passthrough())
245
+ ```
246
+
247
+ ### Effect Schema Example
248
+
249
+ ```typescript
250
+ import { Schema } from "effect"
251
+ import { defineScript, lua } from "upstash-lua"
252
+
253
+ const incr = defineScript({
254
+ name: "incr",
255
+ keys: {
256
+ key: Schema.standardSchemaV1(Schema.String),
257
+ },
258
+ args: {
259
+ amount: Schema.standardSchemaV1(
260
+ Schema.Number.pipe(
261
+ Schema.transform(Schema.String, (n) => String(n), (s) => Number(s))
262
+ )
263
+ ),
264
+ },
265
+ lua: ({ KEYS, ARGV }) => lua`
266
+ return redis.call("INCRBY", ${KEYS.key}, ${ARGV.amount})
267
+ `,
268
+ returns: Schema.standardSchemaV1(Schema.Number),
269
+ })
270
+ ```
271
+
272
+ ## Error Handling
273
+
274
+ Errors are thrown as `Error` objects with descriptive messages when validation fails:
275
+
276
+ ```typescript
277
+ try {
278
+ await script.run(redis, { args: { limit: -1 } })
279
+ } catch (error) {
280
+ if (error instanceof Error) {
281
+ console.error(error.message)
282
+ // "[upstash-lua@0.2.0] Script \"rateLimit\" input validation failed at \"args.limit\": Number must be positive"
283
+ }
284
+ }
285
+ ```
286
+
287
+ Error messages include:
288
+ - The library version
289
+ - The script name
290
+ - The validation path (for input errors)
291
+ - The validation error messages
292
+
293
+ ## How It Works
294
+
295
+ 1. **Define** - Creates script with metadata and computed SHA1
296
+ - If `lua` is a function, it's called with typed `KEYS`/`ARGV` proxies
297
+ - The `lua` template is compiled: `${KEYS.name}` → `KEYS[n]`, `${ARGV.name}` → `ARGV[n]`
298
+ 2. **Validate** - Keys/args are validated against StandardSchemaV1 schemas
299
+ 3. **Transform** - Validated values are transformed (e.g., numbers → strings)
300
+ 4. **Execute** - Uses EVALSHA for efficiency, falls back to SCRIPT LOAD on NOSCRIPT
301
+ 5. **Parse** - Return value is validated/transformed if schema provided
302
+
303
+ The library caches script loading per-client, so concurrent calls share a single SCRIPT LOAD.
304
+
305
+ ## Versioning
306
+
307
+ ```typescript
308
+ import { VERSION } from "upstash-lua"
309
+ console.log(`Using upstash-lua v${VERSION}`)
310
+ ```
311
+
312
+ Errors include the version for debugging:
313
+ ```
314
+ [upstash-lua@0.1.0] Script "rateLimit" input validation failed at "args.limit": ...
315
+ ```
316
+
317
+ ## License
318
+
319
+ MIT
@@ -0,0 +1,250 @@
1
+ import type { RedisLike } from "./redis-like.ts";
2
+ import type { AnyStandardSchema, ScriptCallArgs, StdOutput, StringSchemaRecord } from "./types.ts";
3
+ import { type CompiledLua, type TokenProxy } from "./lua-template.ts";
4
+ /**
5
+ * Represents a defined Lua script with type-safe execution methods.
6
+ *
7
+ * The Script object is created by `defineScript()` and provides methods
8
+ * to execute the script with validated inputs and typed outputs.
9
+ *
10
+ * @typeParam K - The keys schema record
11
+ * @typeParam A - The args schema record
12
+ * @typeParam R - The return type after validation
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const myScript: Script<{ key: z.ZodString }, { limit: z.ZodNumber }, number> = defineScript({
17
+ * name: "myScript",
18
+ * lua: `return redis.call("INCR", KEYS[1])`,
19
+ * keys: { key: z.string() },
20
+ * args: { limit: z.number().transform(String) },
21
+ * returns: z.number(),
22
+ * })
23
+ * ```
24
+ *
25
+ * @since 0.1.0
26
+ */
27
+ export interface Script<K extends StringSchemaRecord, A extends StringSchemaRecord, R> {
28
+ /**
29
+ * Human-readable name of the script.
30
+ * Used in error messages for debugging.
31
+ */
32
+ readonly name: string;
33
+ /**
34
+ * The Lua script source code.
35
+ */
36
+ readonly lua: string;
37
+ /**
38
+ * Ordered list of key names.
39
+ * The order matches KEYS[1], KEYS[2], etc. in the Lua script.
40
+ * Derived from `Object.keys(def.keys)` at definition time.
41
+ */
42
+ readonly keyNames: readonly Extract<keyof K, string>[];
43
+ /**
44
+ * Ordered list of argument names.
45
+ * The order matches ARGV[1], ARGV[2], etc. in the Lua script.
46
+ * Derived from `Object.keys(def.args)` at definition time.
47
+ */
48
+ readonly argNames: readonly Extract<keyof A, string>[];
49
+ /**
50
+ * Executes the script without validating the return value.
51
+ *
52
+ * Use this when you don't need return validation or want to handle
53
+ * the raw Redis response yourself.
54
+ *
55
+ * @param redis - The Redis client to execute on
56
+ * @param input - The keys and args (omit if both are empty)
57
+ * @returns Promise resolving to the raw Redis response
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const raw = await myScript.runRaw(redis, {
62
+ * keys: { key: "test" },
63
+ * args: { limit: 10 },
64
+ * })
65
+ * ```
66
+ *
67
+ * @since 0.1.0
68
+ */
69
+ runRaw(redis: RedisLike, ...input: ScriptCallArgs<K, A>): Promise<unknown>;
70
+ /**
71
+ * Executes the script with full input and return validation.
72
+ *
73
+ * This is the primary method for executing scripts. It:
74
+ * 1. Validates all keys and args against their schemas
75
+ * 2. Transforms validated values (e.g., numbers to strings)
76
+ * 3. Executes the script via EVALSHA (with NOSCRIPT fallback)
77
+ * 4. Validates and transforms the return value (if returns schema provided)
78
+ *
79
+ * @param redis - The Redis client to execute on
80
+ * @param input - The keys and args (omit if both are empty)
81
+ * @returns Promise resolving to the validated and transformed return value
82
+ * @throws {Error} When validation fails
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const result = await myScript.run(redis, {
87
+ * keys: { key: "test" },
88
+ * args: { limit: 10 },
89
+ * })
90
+ * ```
91
+ *
92
+ * @since 0.1.0
93
+ */
94
+ run(redis: RedisLike, ...input: ScriptCallArgs<K, A>): Promise<R>;
95
+ }
96
+ /**
97
+ * Function type for type-safe Lua script definition.
98
+ *
99
+ * Receives typed `KEYS` and `ARGV` proxy objects and returns a `CompiledLua`
100
+ * template created with the `lua` tagged template function.
101
+ *
102
+ * @typeParam K - The keys schema record
103
+ * @typeParam A - The args schema record
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * lua: ({ KEYS, ARGV }) => lua`
108
+ * local key = ${KEYS.userKey}
109
+ * local limit = tonumber(${ARGV.limit})
110
+ * return redis.call("GET", key)
111
+ * `
112
+ * ```
113
+ *
114
+ * @since 0.2.0
115
+ */
116
+ export type LuaFunction<K extends StringSchemaRecord, A extends StringSchemaRecord> = (ctx: {
117
+ KEYS: TokenProxy<K>;
118
+ ARGV: TokenProxy<A>;
119
+ }) => CompiledLua;
120
+ /**
121
+ * Base definition for a Lua script.
122
+ *
123
+ * @typeParam K - The keys schema record
124
+ * @typeParam A - The args schema record
125
+ *
126
+ * @since 0.1.0
127
+ */
128
+ export interface DefineScriptBase<K extends StringSchemaRecord, A extends StringSchemaRecord> {
129
+ /**
130
+ * Human-readable name for the script.
131
+ * Used in error messages for debugging.
132
+ */
133
+ name: string;
134
+ /**
135
+ * The Lua script source code.
136
+ *
137
+ * Can be either:
138
+ * - A plain string (for raw `.lua` files or manual scripts)
139
+ * - A function receiving typed `KEYS`/`ARGV` proxies and returning a `lua` template
140
+ *
141
+ * When using the function form, you get:
142
+ * - Autocomplete for `KEYS.*` and `ARGV.*`
143
+ * - Compile-time errors for invalid key/arg references
144
+ * - Automatic compilation of `${KEYS.name}` to `KEYS[n]`
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * // String form (no type safety for KEYS/ARGV):
149
+ * lua: `return redis.call("GET", KEYS[1])`
150
+ *
151
+ * // Function form (type-safe):
152
+ * lua: ({ KEYS, ARGV }) => lua`
153
+ * local key = ${KEYS.userKey}
154
+ * return redis.call("GET", key)
155
+ * `
156
+ * ```
157
+ */
158
+ lua: string | LuaFunction<K, A>;
159
+ /**
160
+ * Record of key schemas.
161
+ *
162
+ * **Important:** The order of keys in this object determines the order
163
+ * they appear in KEYS[1], KEYS[2], etc. Define keys using object literal
164
+ * syntax in the intended order. Do not spread from unknown sources.
165
+ *
166
+ * Each schema must output a string (use `.transform(String)` if needed).
167
+ */
168
+ keys?: K;
169
+ /**
170
+ * Record of argument schemas.
171
+ *
172
+ * **Important:** The order of args in this object determines the order
173
+ * they appear in ARGV[1], ARGV[2], etc. Define args using object literal
174
+ * syntax in the intended order. Do not spread from unknown sources.
175
+ *
176
+ * Each schema must output a string (use `.transform(String)` if needed).
177
+ */
178
+ args?: A;
179
+ }
180
+ /**
181
+ * Defines a type-safe Lua script for execution on Upstash Redis.
182
+ *
183
+ * This function creates a Script object that:
184
+ * - Validates keys and args using StandardSchemaV1 schemas
185
+ * - Transforms values (e.g., numbers to strings for Redis)
186
+ * - Executes efficiently via EVALSHA with automatic NOSCRIPT fallback
187
+ * - Validates and transforms return values
188
+ *
189
+ * **Key ordering:** The order of keys/args in the definition object determines
190
+ * their order in KEYS[1], KEYS[2] and ARGV[1], ARGV[2], etc. Always define
191
+ * using object literal syntax in the intended order.
192
+ *
193
+ * @param def - Script definition with name, lua, keys, args, and optional returns
194
+ * @returns A Script object with `run()` and `runRaw()` methods
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * import { z } from "zod"
199
+ * import { defineScript } from "upstash-lua"
200
+ *
201
+ * const rateLimit = defineScript({
202
+ * name: "rateLimit",
203
+ * lua: `
204
+ * local current = redis.call("INCR", KEYS[1])
205
+ * if current == 1 then
206
+ * redis.call("EXPIRE", KEYS[1], ARGV[2])
207
+ * end
208
+ * local allowed = current <= tonumber(ARGV[1]) and 1 or 0
209
+ * return { allowed, tonumber(ARGV[1]) - current }
210
+ * `,
211
+ * keys: {
212
+ * key: z.string(),
213
+ * },
214
+ * args: {
215
+ * limit: z.number().int().positive().transform(String),
216
+ * windowSeconds: z.number().int().positive().transform(String),
217
+ * },
218
+ * returns: z.tuple([z.number(), z.number()]).transform(([allowed, rem]) => ({
219
+ * allowed: allowed === 1,
220
+ * remaining: rem,
221
+ * })),
222
+ * })
223
+ *
224
+ * const result = await rateLimit.run(redis, {
225
+ * keys: { key: "rl:user:123" },
226
+ * args: { limit: 10, windowSeconds: 60 },
227
+ * })
228
+ * // result: { allowed: boolean, remaining: number }
229
+ * ```
230
+ *
231
+ * @see https://github.com/your-org/upstash-lua for full documentation
232
+ * @since 0.1.0
233
+ */
234
+ export declare function defineScript<const K extends StringSchemaRecord, const A extends StringSchemaRecord, const Ret extends AnyStandardSchema>(def: DefineScriptBase<K, A> & {
235
+ returns: Ret;
236
+ }): Script<K, A, StdOutput<Ret>>;
237
+ /**
238
+ * Defines a Lua script without return validation.
239
+ *
240
+ * When no `returns` schema is provided, `run()` returns `unknown`.
241
+ *
242
+ * @param def - Script definition with name, lua, keys, and args
243
+ * @returns A Script object with `run()` returning `unknown`
244
+ *
245
+ * @since 0.1.0
246
+ */
247
+ export declare function defineScript<const K extends StringSchemaRecord, const A extends StringSchemaRecord>(def: DefineScriptBase<K, A> & {
248
+ returns?: undefined;
249
+ }): Script<K, A, unknown>;
250
+ //# sourceMappingURL=define-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-script.d.ts","sourceRoot":"","sources":["../src/define-script.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EAEd,SAAS,EACT,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAInB,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,UAAU,EAIhB,MAAM,mBAAmB,CAAA;AAE1B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,MAAM,CAAC,CAAC,SAAS,kBAAkB,EAAE,CAAC,SAAS,kBAAkB,EAAE,CAAC;IACnF;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IAEpB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,CAAA;IAEtD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,CAAA;IAEtD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE1E;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CAClE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,kBAAkB,EAAE,CAAC,SAAS,kBAAkB,IAAI,CAAC,GAAG,EAAE;IAC1F,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;IACnB,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;CACpB,KAAK,WAAW,CAAA;AAEjB;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,kBAAkB,EAAE,CAAC,SAAS,kBAAkB;IAC1F;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAE/B;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,CAAC,CAAA;IAER;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,CAAC,CAAA;CACT;AAkGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,YAAY,CAC1B,KAAK,CAAC,CAAC,SAAS,kBAAkB,EAClC,KAAK,CAAC,CAAC,SAAS,kBAAkB,EAClC,KAAK,CAAC,GAAG,SAAS,iBAAiB,EACnC,GAAG,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;AAE/E;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,KAAK,CAAC,CAAC,SAAS,kBAAkB,EAClC,KAAK,CAAC,CAAC,SAAS,kBAAkB,EAClC,GAAG,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Represents a validation issue from a StandardSchemaV1 schema.
3
+ * This is a simplified representation that works across different schema libraries.
4
+ *
5
+ * @since 0.1.0
6
+ */
7
+ export interface ValidationIssue {
8
+ /** Human-readable error message */
9
+ readonly message: string;
10
+ /** Path to the invalid value within the input */
11
+ readonly path?: ReadonlyArray<PropertyKey>;
12
+ }
13
+ /**
14
+ * Error thrown when script input validation fails.
15
+ *
16
+ * This error is thrown when keys or args fail to validate against their
17
+ * respective StandardSchemaV1 schemas before the script is executed.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * try {
22
+ * await myScript.run(redis, { keys: { key: "" }, args: { limit: -1 } })
23
+ * } catch (error) {
24
+ * if (error instanceof ScriptInputError) {
25
+ * console.error(`Script: ${error.scriptName}`)
26
+ * console.error(`Field: ${error.path}`) // e.g., "args.limit"
27
+ * console.error(`Issues:`, error.issues)
28
+ * }
29
+ * }
30
+ * ```
31
+ *
32
+ * @since 0.1.0
33
+ */
34
+ export declare class ScriptInputError extends Error {
35
+ /**
36
+ * The name of the script that failed validation.
37
+ * Matches the `name` property in the script definition.
38
+ */
39
+ readonly scriptName: string;
40
+ /**
41
+ * The path to the invalid field.
42
+ * Format: `"keys.<fieldName>"` or `"args.<fieldName>"`
43
+ *
44
+ * @example "args.limit", "keys.userId"
45
+ */
46
+ readonly path: string;
47
+ /**
48
+ * Array of validation issues from the schema library.
49
+ * Each issue contains at least a `message` property.
50
+ */
51
+ readonly issues: readonly ValidationIssue[];
52
+ /**
53
+ * Creates a new ScriptInputError.
54
+ *
55
+ * @param scriptName - Name of the script that failed validation
56
+ * @param path - Path to the invalid field (e.g., "args.limit")
57
+ * @param issues - Array of validation issues from the schema
58
+ */
59
+ constructor(scriptName: string, path: string, issues: readonly ValidationIssue[]);
60
+ }
61
+ /**
62
+ * Error thrown when script return value validation fails.
63
+ *
64
+ * This error is thrown when the Redis response fails to validate against
65
+ * the `returns` StandardSchemaV1 schema after script execution.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * try {
70
+ * await myScript.run(redis, { keys: { key: "test" } })
71
+ * } catch (error) {
72
+ * if (error instanceof ScriptReturnError) {
73
+ * console.error(`Script: ${error.scriptName}`)
74
+ * console.error(`Raw response:`, error.raw)
75
+ * console.error(`Issues:`, error.issues)
76
+ * }
77
+ * }
78
+ * ```
79
+ *
80
+ * @since 0.1.0
81
+ */
82
+ export declare class ScriptReturnError extends Error {
83
+ /**
84
+ * The name of the script whose return validation failed.
85
+ * Matches the `name` property in the script definition.
86
+ */
87
+ readonly scriptName: string;
88
+ /**
89
+ * Array of validation issues from the schema library.
90
+ * Each issue contains at least a `message` property.
91
+ */
92
+ readonly issues: readonly ValidationIssue[];
93
+ /**
94
+ * The raw value returned from Redis before validation.
95
+ * Useful for debugging schema mismatches.
96
+ */
97
+ readonly raw: unknown;
98
+ /**
99
+ * Creates a new ScriptReturnError.
100
+ *
101
+ * @param scriptName - Name of the script that failed validation
102
+ * @param issues - Array of validation issues from the schema
103
+ * @param raw - The raw Redis response that failed validation
104
+ */
105
+ constructor(scriptName: string, issues: readonly ValidationIssue[], raw: unknown);
106
+ }
107
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAA;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAE3B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAE3C;;;;;;OAMG;gBAED,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,eAAe,EAAE;CAiBrC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAE3B;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAE3C;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IAErB;;;;;;OAMG;gBAED,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,eAAe,EAAE,EAClC,GAAG,EAAE,OAAO;CAiBf"}