@outfitter/contracts 0.3.0 → 0.4.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.
Files changed (41) hide show
  1. package/dist/actions.d.ts +4 -4
  2. package/dist/adapters.d.ts +1 -1
  3. package/dist/assert/index.d.ts +2 -2
  4. package/dist/capabilities.d.ts +1 -1
  5. package/dist/context.d.ts +4 -4
  6. package/dist/envelope.d.ts +2 -2
  7. package/dist/envelope.js +4 -4
  8. package/dist/errors.d.ts +1 -1
  9. package/dist/handler.d.ts +3 -3
  10. package/dist/index.d.ts +18 -17
  11. package/dist/index.js +39 -35
  12. package/dist/logging.d.ts +1 -1
  13. package/dist/recovery.d.ts +2 -2
  14. package/dist/redactor.d.ts +1 -1
  15. package/dist/resilience.d.ts +2 -2
  16. package/dist/result/index.d.ts +2 -2
  17. package/dist/result/utilities.d.ts +1 -1
  18. package/dist/schema.d.ts +2 -0
  19. package/dist/schema.js +7 -0
  20. package/dist/serialization.d.ts +2 -2
  21. package/dist/serialization.js +2 -2
  22. package/dist/shared/@outfitter/{contracts-ss9vjjft.d.ts → contracts-0akf2sm6.d.ts} +10 -10
  23. package/dist/shared/@outfitter/{contracts-25bkj17f.d.ts → contracts-1waabxbk.d.ts} +10 -10
  24. package/dist/shared/@outfitter/{contracts-j08e95jw.d.ts → contracts-31penhwa.d.ts} +1 -1
  25. package/dist/shared/@outfitter/{contracts-sf1z80yc.d.ts → contracts-56pcsavx.d.ts} +17 -17
  26. package/dist/shared/@outfitter/{contracts-btg89x4h.js → contracts-85nd53s9.js} +4 -4
  27. package/dist/shared/@outfitter/{contracts-bdwg55c5.d.ts → contracts-95cc3y06.d.ts} +13 -13
  28. package/dist/shared/@outfitter/{contracts-6j6z9dsd.d.ts → contracts-9wtm5nsw.d.ts} +1 -1
  29. package/dist/shared/@outfitter/{contracts-jggbn5tn.d.ts → contracts-e4m948m7.d.ts} +10 -10
  30. package/dist/shared/@outfitter/{contracts-evxky148.d.ts → contracts-k71jqd1m.d.ts} +1 -1
  31. package/dist/shared/@outfitter/{contracts-18vcxecr.d.ts → contracts-mmg0npfk.d.ts} +1 -1
  32. package/dist/shared/@outfitter/contracts-t79engf9.d.ts +60 -0
  33. package/dist/shared/@outfitter/contracts-wfht4q2b.js +341 -0
  34. package/dist/validation.d.ts +2 -2
  35. package/package.json +9 -2
  36. package/dist/shared/@outfitter/{contracts-r35bn9p6.d.ts → contracts-3gswmhb1.d.ts} +2 -2
  37. package/dist/shared/@outfitter/{contracts-5k6q4n48.js → contracts-3wj7xghe.js} +5 -5
  38. package/dist/shared/@outfitter/{contracts-e70qdasg.d.ts → contracts-9yd4vrjg.d.ts} +12 -12
  39. package/dist/shared/@outfitter/{contracts-93dx53mt.d.ts → contracts-c2cfj172.d.ts} +32 -32
  40. package/dist/shared/@outfitter/{contracts-2g8r01zf.d.ts → contracts-rwzqy9rn.d.ts} +10 -10
  41. package/dist/shared/@outfitter/{contracts-bb4hjt8g.d.ts → contracts-y8f0m1ze.d.ts} +1 -1
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * JSON Schema representation.
4
+ */
5
+ interface JsonSchema {
6
+ $defs?: Record<string, JsonSchema>;
7
+ $ref?: string;
8
+ $schema?: string;
9
+ additionalProperties?: boolean | JsonSchema;
10
+ allOf?: JsonSchema[];
11
+ anyOf?: JsonSchema[];
12
+ const?: unknown;
13
+ default?: unknown;
14
+ definitions?: Record<string, JsonSchema>;
15
+ description?: string;
16
+ enum?: unknown[];
17
+ exclusiveMaximum?: number;
18
+ exclusiveMinimum?: number;
19
+ format?: string;
20
+ items?: JsonSchema | JsonSchema[];
21
+ maximum?: number;
22
+ maxLength?: number;
23
+ minimum?: number;
24
+ minLength?: number;
25
+ not?: JsonSchema | Record<string, never>;
26
+ oneOf?: JsonSchema[];
27
+ pattern?: string;
28
+ properties?: Record<string, JsonSchema>;
29
+ required?: string[];
30
+ type?: string;
31
+ }
32
+ /**
33
+ * Convert a Zod schema to JSON Schema format.
34
+ *
35
+ * This is a simplified converter that handles common Zod types.
36
+ * For complex schemas, consider using a full zod-to-json-schema library.
37
+ *
38
+ * @param schema - Zod schema to convert
39
+ * @returns JSON Schema representation
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const zodSchema = z.object({
44
+ * name: z.string(),
45
+ * age: z.number().optional(),
46
+ * });
47
+ *
48
+ * const jsonSchema = zodToJsonSchema(zodSchema);
49
+ * // {
50
+ * // type: "object",
51
+ * // properties: {
52
+ * // name: { type: "string" },
53
+ * // age: { type: "number" },
54
+ * // },
55
+ * // required: ["name"],
56
+ * // }
57
+ * ```
58
+ */
59
+ declare function zodToJsonSchema(schema: z.ZodType<unknown>): JsonSchema;
60
+ export { JsonSchema, zodToJsonSchema };
@@ -0,0 +1,341 @@
1
+ // @bun
2
+ // packages/contracts/src/schema.ts
3
+ function zodToJsonSchema(schema) {
4
+ return convertZodType(schema);
5
+ }
6
+ function getDef(schemaOrDef) {
7
+ if (!schemaOrDef) {
8
+ return;
9
+ }
10
+ if (schemaOrDef._def) {
11
+ return schemaOrDef._def;
12
+ }
13
+ if (schemaOrDef.def) {
14
+ return schemaOrDef.def;
15
+ }
16
+ return schemaOrDef;
17
+ }
18
+ function getDescription(schema, def) {
19
+ if (typeof schema?.description === "string") {
20
+ return schema.description;
21
+ }
22
+ if (typeof def?.description === "string") {
23
+ return def.description;
24
+ }
25
+ return;
26
+ }
27
+ function convertZodType(schema) {
28
+ const def = getDef(schema);
29
+ if (!def) {
30
+ return {};
31
+ }
32
+ const typeName = def.typeName ?? def.type;
33
+ let jsonSchema;
34
+ switch (typeName) {
35
+ case "ZodString":
36
+ case "string":
37
+ jsonSchema = convertString(def);
38
+ break;
39
+ case "ZodNumber":
40
+ case "number":
41
+ jsonSchema = convertNumber(def);
42
+ break;
43
+ case "ZodBoolean":
44
+ case "boolean":
45
+ jsonSchema = { type: "boolean" };
46
+ break;
47
+ case "ZodNull":
48
+ case "null":
49
+ jsonSchema = { type: "null" };
50
+ break;
51
+ case "ZodUndefined":
52
+ case "undefined":
53
+ jsonSchema = {};
54
+ break;
55
+ case "ZodArray":
56
+ case "array":
57
+ jsonSchema = convertArray(def);
58
+ break;
59
+ case "ZodObject":
60
+ case "object":
61
+ jsonSchema = convertObject(def);
62
+ break;
63
+ case "ZodOptional":
64
+ case "optional":
65
+ jsonSchema = convertZodType(def.innerType);
66
+ break;
67
+ case "ZodNullable":
68
+ case "nullable":
69
+ jsonSchema = {
70
+ anyOf: [convertZodType(def.innerType), { type: "null" }]
71
+ };
72
+ break;
73
+ case "ZodDefault":
74
+ case "default": {
75
+ const defaultValue = typeof def.defaultValue === "function" ? def.defaultValue() : def.defaultValue;
76
+ jsonSchema = {
77
+ ...convertZodType(def.innerType),
78
+ default: defaultValue
79
+ };
80
+ break;
81
+ }
82
+ case "ZodEnum":
83
+ case "enum": {
84
+ const values = def.values ?? Object.values(def.entries ?? {});
85
+ jsonSchema = {
86
+ type: "string",
87
+ enum: values
88
+ };
89
+ break;
90
+ }
91
+ case "ZodNativeEnum":
92
+ jsonSchema = {
93
+ enum: Object.values(def.values ?? def.entries ?? {})
94
+ };
95
+ break;
96
+ case "ZodLiteral":
97
+ case "literal": {
98
+ const literalValues = Array.isArray(def.values) ? def.values : [def.value].filter((value) => value !== undefined);
99
+ if (literalValues.length > 1) {
100
+ jsonSchema = {
101
+ enum: literalValues
102
+ };
103
+ break;
104
+ }
105
+ jsonSchema = literalValues.length ? {
106
+ const: literalValues[0]
107
+ } : {};
108
+ break;
109
+ }
110
+ case "ZodUnion":
111
+ case "union":
112
+ jsonSchema = {
113
+ anyOf: def.options.map(convertZodType)
114
+ };
115
+ break;
116
+ case "ZodIntersection":
117
+ case "intersection":
118
+ jsonSchema = {
119
+ allOf: [convertZodType(def.left), convertZodType(def.right)]
120
+ };
121
+ break;
122
+ case "ZodRecord":
123
+ case "record":
124
+ jsonSchema = {
125
+ type: "object",
126
+ additionalProperties: def.valueType ? convertZodType(def.valueType) : {}
127
+ };
128
+ break;
129
+ case "ZodTuple":
130
+ case "tuple":
131
+ jsonSchema = {
132
+ type: "array",
133
+ items: def.items.map(convertZodType)
134
+ };
135
+ break;
136
+ case "ZodAny":
137
+ case "any":
138
+ jsonSchema = {};
139
+ break;
140
+ case "ZodUnknown":
141
+ case "unknown":
142
+ jsonSchema = {};
143
+ break;
144
+ case "ZodVoid":
145
+ case "void":
146
+ jsonSchema = {};
147
+ break;
148
+ case "ZodNever":
149
+ case "never":
150
+ jsonSchema = { not: {} };
151
+ break;
152
+ case "ZodEffects":
153
+ jsonSchema = convertZodType(def.schema);
154
+ break;
155
+ case "ZodPipeline":
156
+ case "pipe": {
157
+ const outputDef = getDef(def.out);
158
+ const outputType = outputDef?.typeName ?? outputDef?.type;
159
+ jsonSchema = outputType === "transform" ? convertZodType(def.in) : convertZodType(def.out);
160
+ break;
161
+ }
162
+ case "ZodLazy":
163
+ case "lazy":
164
+ jsonSchema = {};
165
+ break;
166
+ default:
167
+ jsonSchema = {};
168
+ break;
169
+ }
170
+ const description = getDescription(schema, def);
171
+ if (description && !jsonSchema.description) {
172
+ jsonSchema.description = description;
173
+ }
174
+ return jsonSchema;
175
+ }
176
+ function convertString(def) {
177
+ const schema = { type: "string" };
178
+ if (def.checks) {
179
+ for (const check of def.checks) {
180
+ const normalizedCheck = check?._zod?.def ?? check?.def ?? check;
181
+ if (normalizedCheck?.kind) {
182
+ switch (normalizedCheck.kind) {
183
+ case "min":
184
+ schema.minLength = normalizedCheck.value;
185
+ break;
186
+ case "max":
187
+ schema.maxLength = normalizedCheck.value;
188
+ break;
189
+ case "length":
190
+ schema.minLength = normalizedCheck.value;
191
+ schema.maxLength = normalizedCheck.value;
192
+ break;
193
+ case "email":
194
+ schema.pattern = "^[^@]+@[^@]+\\.[^@]+$";
195
+ break;
196
+ case "url":
197
+ schema.pattern = "^https?://";
198
+ break;
199
+ case "uuid":
200
+ schema.pattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";
201
+ break;
202
+ case "regex":
203
+ schema.pattern = normalizedCheck.regex?.source ?? normalizedCheck.pattern?.source ?? (typeof normalizedCheck.pattern === "string" ? normalizedCheck.pattern : undefined);
204
+ break;
205
+ default:
206
+ break;
207
+ }
208
+ continue;
209
+ }
210
+ if (!normalizedCheck?.check) {
211
+ continue;
212
+ }
213
+ switch (normalizedCheck.check) {
214
+ case "min_length":
215
+ schema.minLength = normalizedCheck.minimum;
216
+ break;
217
+ case "max_length":
218
+ schema.maxLength = normalizedCheck.maximum;
219
+ break;
220
+ case "string_format":
221
+ if (normalizedCheck.pattern) {
222
+ schema.pattern = typeof normalizedCheck.pattern === "string" ? normalizedCheck.pattern : normalizedCheck.pattern.source;
223
+ }
224
+ if (normalizedCheck.format && normalizedCheck.format !== "regex") {
225
+ schema.format = normalizedCheck.format;
226
+ }
227
+ break;
228
+ default:
229
+ break;
230
+ }
231
+ }
232
+ }
233
+ return schema;
234
+ }
235
+ function convertNumber(def) {
236
+ const schema = { type: "number" };
237
+ if (def.checks) {
238
+ for (const check of def.checks) {
239
+ const normalizedCheck = check?._zod?.def ?? check?.def ?? check;
240
+ if (normalizedCheck?.kind) {
241
+ switch (normalizedCheck.kind) {
242
+ case "min":
243
+ schema.minimum = normalizedCheck.value;
244
+ break;
245
+ case "max":
246
+ schema.maximum = normalizedCheck.value;
247
+ break;
248
+ case "int":
249
+ schema.type = "integer";
250
+ break;
251
+ default:
252
+ break;
253
+ }
254
+ continue;
255
+ }
256
+ if (!normalizedCheck?.check) {
257
+ continue;
258
+ }
259
+ switch (normalizedCheck.check) {
260
+ case "greater_than":
261
+ if (normalizedCheck.inclusive) {
262
+ schema.minimum = normalizedCheck.value;
263
+ } else {
264
+ schema.exclusiveMinimum = normalizedCheck.value;
265
+ }
266
+ break;
267
+ case "less_than":
268
+ if (normalizedCheck.inclusive) {
269
+ schema.maximum = normalizedCheck.value;
270
+ } else {
271
+ schema.exclusiveMaximum = normalizedCheck.value;
272
+ }
273
+ break;
274
+ case "number_format":
275
+ if (normalizedCheck.format === "int" || normalizedCheck.format === "safeint") {
276
+ schema.type = "integer";
277
+ }
278
+ break;
279
+ default:
280
+ break;
281
+ }
282
+ }
283
+ }
284
+ return schema;
285
+ }
286
+ function convertArray(def) {
287
+ const element = def.element ?? def.type;
288
+ const schema = {
289
+ type: "array",
290
+ items: element ? convertZodType(element) : {}
291
+ };
292
+ return schema;
293
+ }
294
+ function isFieldOptional(fieldDef) {
295
+ if (!(fieldDef?.typeName || fieldDef?.type)) {
296
+ return false;
297
+ }
298
+ const typeName = fieldDef.typeName ?? fieldDef.type;
299
+ if (typeName === "ZodOptional" || typeName === "ZodDefault" || typeName === "optional" || typeName === "default") {
300
+ return true;
301
+ }
302
+ if (typeName === "ZodEffects") {
303
+ return isFieldOptional(getDef(fieldDef.schema));
304
+ }
305
+ if (typeName === "ZodPipeline" || typeName === "pipe") {
306
+ const inputOptional = isFieldOptional(getDef(fieldDef.in));
307
+ const outputDef = getDef(fieldDef.out);
308
+ const outputType = outputDef?.typeName ?? outputDef?.type;
309
+ if (outputType === "transform") {
310
+ return inputOptional;
311
+ }
312
+ const outputOptional = isFieldOptional(outputDef);
313
+ return inputOptional && outputOptional;
314
+ }
315
+ if (typeName === "ZodNullable" || typeName === "nullable") {
316
+ return isFieldOptional(getDef(fieldDef.innerType));
317
+ }
318
+ return false;
319
+ }
320
+ function convertObject(def) {
321
+ const properties = {};
322
+ const required = [];
323
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
324
+ for (const [key, value] of Object.entries(shape ?? {})) {
325
+ properties[key] = convertZodType(value);
326
+ const fieldDef = getDef(value);
327
+ if (!isFieldOptional(fieldDef)) {
328
+ required.push(key);
329
+ }
330
+ }
331
+ const schema = {
332
+ type: "object",
333
+ properties
334
+ };
335
+ if (required.length > 0) {
336
+ schema.required = required;
337
+ }
338
+ return schema;
339
+ }
340
+
341
+ export { zodToJsonSchema };
@@ -1,3 +1,3 @@
1
- import { createValidator, validateInput } from "./shared/@outfitter/contracts-6j6z9dsd";
2
- import "./shared/@outfitter/contracts-r35bn9p6";
1
+ import { createValidator, validateInput } from "./shared/@outfitter/contracts-9wtm5nsw.js";
2
+ import "./shared/@outfitter/contracts-3gswmhb1.js";
3
3
  export { validateInput, createValidator };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@outfitter/contracts",
3
3
  "description": "Result/Error patterns, error taxonomy, and handler contracts for Outfitter",
4
- "version": "0.3.0",
4
+ "version": "0.4.1",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -100,6 +100,12 @@
100
100
  "default": "./dist/result/utilities.js"
101
101
  }
102
102
  },
103
+ "./schema": {
104
+ "import": {
105
+ "types": "./dist/schema.d.ts",
106
+ "default": "./dist/schema.js"
107
+ }
108
+ },
103
109
  "./serialization": {
104
110
  "import": {
105
111
  "types": "./dist/serialization.d.ts",
@@ -120,7 +126,8 @@
120
126
  "lint:fix": "biome lint --write ./src",
121
127
  "test": "bun test",
122
128
  "typecheck": "tsc --noEmit",
123
- "clean": "rm -rf dist"
129
+ "clean": "rm -rf dist",
130
+ "prepublishOnly": "bun ../../scripts/check-publish-manifest.ts"
124
131
  },
125
132
  "dependencies": {
126
133
  "better-result": "^2.5.0",
@@ -90,17 +90,17 @@ type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES][keyof (typeof ER
90
90
  interface SerializedError {
91
91
  _tag: string;
92
92
  category: ErrorCategory;
93
- message: string;
94
93
  context?: Record<string, unknown>;
94
+ message: string;
95
95
  }
96
96
  /**
97
97
  * Base interface for OutfitterError properties.
98
98
  * All concrete error classes must include these fields.
99
99
  */
100
100
  interface KitErrorProps {
101
- message: string;
102
101
  category: ErrorCategory;
103
102
  context?: Record<string, unknown>;
103
+ message: string;
104
104
  }
105
105
  /**
106
106
  * Get CLI exit code for an error category.
@@ -1,4 +1,9 @@
1
1
  // @bun
2
+ import {
3
+ DEFAULT_PATTERNS,
4
+ DEFAULT_SENSITIVE_KEYS,
5
+ createRedactor
6
+ } from "./contracts-s15x2rs4.js";
2
7
  import {
3
8
  AlreadyExistsError,
4
9
  AmbiguousError,
@@ -14,11 +19,6 @@ import {
14
19
  TimeoutError,
15
20
  ValidationError
16
21
  } from "./contracts-phjhz5q3.js";
17
- import {
18
- DEFAULT_PATTERNS,
19
- DEFAULT_SENSITIVE_KEYS,
20
- createRedactor
21
- } from "./contracts-s15x2rs4.js";
22
22
 
23
23
  // packages/contracts/src/serialization.ts
24
24
  import { Result } from "better-result";
@@ -2,25 +2,25 @@
2
2
  * Configuration for creating a redactor.
3
3
  */
4
4
  interface RedactorConfig {
5
- /** Regex patterns to match and redact */
6
- patterns: RegExp[];
5
+ /** Whether to redact recursively in nested objects (default: true) */
6
+ deep?: boolean;
7
7
  /** Object keys whose values should always be redacted */
8
8
  keys: string[];
9
+ /** Regex patterns to match and redact */
10
+ patterns: RegExp[];
9
11
  /** Replacement string (default: "[REDACTED]") */
10
12
  replacement?: string;
11
- /** Whether to redact recursively in nested objects (default: true) */
12
- deep?: boolean;
13
13
  }
14
14
  /**
15
15
  * Redaction event for audit logging.
16
16
  */
17
17
  interface RedactionEvent {
18
- /** Type of redaction applied */
19
- redactedBy: "pattern" | "key";
20
18
  /** Identifier of the pattern/key that matched */
21
19
  matcher: string;
22
20
  /** Location in the object path (e.g., "config.auth.apiKey") */
23
21
  path: string;
22
+ /** Type of redaction applied */
23
+ redactedBy: "pattern" | "key";
24
24
  }
25
25
  /**
26
26
  * Callback for redaction events.
@@ -49,16 +49,16 @@ type RedactionCallback = (event: RedactionEvent) => void;
49
49
  * ```
50
50
  */
51
51
  interface Redactor {
52
- /** Redact sensitive values from an object (deep) */
53
- redact<T>(value: T): T;
54
- /** Redact sensitive values from a string */
55
- redactString(value: string): string;
56
- /** Check if a key name is sensitive */
57
- isSensitiveKey(key: string): boolean;
58
52
  /** Add a pattern at runtime */
59
53
  addPattern(pattern: RegExp): void;
60
54
  /** Add a sensitive key at runtime */
61
55
  addSensitiveKey(key: string): void;
56
+ /** Check if a key name is sensitive */
57
+ isSensitiveKey(key: string): boolean;
58
+ /** Redact sensitive values from an object (deep) */
59
+ redact<T>(value: T): T;
60
+ /** Redact sensitive values from a string */
61
+ redactString(value: string): string;
62
62
  }
63
63
  /**
64
64
  * Default patterns for common secrets.
@@ -6,39 +6,39 @@ import { Result } from "better-result";
6
6
  /** Error during indexing operations */
7
7
  interface IndexError {
8
8
  readonly _tag: "IndexError";
9
- readonly message: string;
10
9
  readonly cause?: unknown;
10
+ readonly message: string;
11
11
  }
12
12
  /** Error during cache operations */
13
13
  interface CacheError {
14
14
  readonly _tag: "CacheError";
15
- readonly message: string;
16
15
  readonly cause?: unknown;
16
+ readonly message: string;
17
17
  }
18
18
  /** Error during auth/credential operations */
19
19
  interface AdapterAuthError {
20
20
  readonly _tag: "AdapterAuthError";
21
- readonly message: string;
22
21
  readonly cause?: unknown;
22
+ readonly message: string;
23
23
  }
24
24
  /** Error during storage operations */
25
25
  interface StorageError {
26
26
  readonly _tag: "StorageError";
27
- readonly message: string;
28
27
  readonly cause?: unknown;
28
+ readonly message: string;
29
29
  }
30
30
  /**
31
31
  * Search options for index adapter.
32
32
  */
33
33
  interface SearchOptions {
34
+ /** Fields to boost in relevance scoring */
35
+ boostFields?: string[];
36
+ /** Field-specific filters */
37
+ filters?: Record<string, unknown>;
34
38
  /** Maximum results to return */
35
39
  limit?: number;
36
40
  /** Offset for pagination */
37
41
  offset?: number;
38
- /** Field-specific filters */
39
- filters?: Record<string, unknown>;
40
- /** Fields to boost in relevance scoring */
41
- boostFields?: string[];
42
42
  }
43
43
  /**
44
44
  * Search result from index adapter.
@@ -50,10 +50,10 @@ interface SearchResult<T> {
50
50
  score: number;
51
51
  highlights?: Record<string, string[]>;
52
52
  }>;
53
- /** Total number of matches (for pagination) */
54
- total: number;
55
53
  /** Search execution time in milliseconds */
56
54
  took: number;
55
+ /** Total number of matches (for pagination) */
56
+ total: number;
57
57
  }
58
58
  /**
59
59
  * Index statistics.
@@ -61,10 +61,10 @@ interface SearchResult<T> {
61
61
  interface IndexStats {
62
62
  /** Total documents indexed */
63
63
  documentCount: number;
64
- /** Index size in bytes (if available) */
65
- sizeBytes?: number;
66
64
  /** Last update timestamp */
67
65
  lastUpdated: Date | null;
66
+ /** Index size in bytes (if available) */
67
+ sizeBytes?: number;
68
68
  }
69
69
  /**
70
70
  * Index adapter - pluggable full-text search backends.
@@ -86,14 +86,14 @@ interface IndexStats {
86
86
  * ```
87
87
  */
88
88
  interface IndexAdapter<T> {
89
+ /** Clear all indexed documents */
90
+ clear(): Promise<Result<void, IndexError>>;
89
91
  /** Add or update documents in the index */
90
92
  index(items: T[]): Promise<Result<void, IndexError>>;
91
- /** Full-text search with optional filters */
92
- search(query: string, options?: SearchOptions): Promise<Result<SearchResult<T>, IndexError>>;
93
93
  /** Remove documents by ID */
94
94
  remove(ids: string[]): Promise<Result<void, IndexError>>;
95
- /** Clear all indexed documents */
96
- clear(): Promise<Result<void, IndexError>>;
95
+ /** Full-text search with optional filters */
96
+ search(query: string, options?: SearchOptions): Promise<Result<SearchResult<T>, IndexError>>;
97
97
  /** Get index statistics */
98
98
  stats(): Promise<Result<IndexStats, IndexError>>;
99
99
  }
@@ -113,18 +113,18 @@ interface IndexAdapter<T> {
113
113
  * ```
114
114
  */
115
115
  interface CacheAdapter<T> {
116
- /** Get cached value, null if not found or expired */
117
- get(key: string): Promise<Result<T | null, CacheError>>;
118
- /** Set value with optional TTL in seconds */
119
- set(key: string, value: T, ttlSeconds?: number): Promise<Result<void, CacheError>>;
120
- /** Delete cached value, returns true if existed */
121
- delete(key: string): Promise<Result<boolean, CacheError>>;
122
116
  /** Clear all cached values */
123
117
  clear(): Promise<Result<void, CacheError>>;
124
- /** Check if key exists (without retrieving value) */
125
- has(key: string): Promise<Result<boolean, CacheError>>;
118
+ /** Delete cached value, returns true if existed */
119
+ delete(key: string): Promise<Result<boolean, CacheError>>;
120
+ /** Get cached value, null if not found or expired */
121
+ get(key: string): Promise<Result<T | null, CacheError>>;
126
122
  /** Get multiple values at once */
127
123
  getMany(keys: string[]): Promise<Result<Map<string, T>, CacheError>>;
124
+ /** Check if key exists (without retrieving value) */
125
+ has(key: string): Promise<Result<boolean, CacheError>>;
126
+ /** Set value with optional TTL in seconds */
127
+ set(key: string, value: T, ttlSeconds?: number): Promise<Result<void, CacheError>>;
128
128
  }
129
129
  /**
130
130
  * Auth adapter - pluggable credential storage.
@@ -140,14 +140,14 @@ interface CacheAdapter<T> {
140
140
  * ```
141
141
  */
142
142
  interface AuthAdapter {
143
- /** Retrieve credential by key */
144
- get(key: string): Promise<Result<string | null, AdapterAuthError>>;
145
- /** Store credential */
146
- set(key: string, value: string): Promise<Result<void, AdapterAuthError>>;
147
143
  /** Remove credential */
148
144
  delete(key: string): Promise<Result<boolean, AdapterAuthError>>;
145
+ /** Retrieve credential by key */
146
+ get(key: string): Promise<Result<string | null, AdapterAuthError>>;
149
147
  /** List available credential keys (not values) */
150
148
  list(): Promise<Result<string[], AdapterAuthError>>;
149
+ /** Store credential */
150
+ set(key: string, value: string): Promise<Result<void, AdapterAuthError>>;
151
151
  }
152
152
  /**
153
153
  * Storage adapter - pluggable blob/file storage.
@@ -163,20 +163,20 @@ interface AuthAdapter {
163
163
  * ```
164
164
  */
165
165
  interface StorageAdapter {
166
- /** Read file contents */
167
- read(path: string): Promise<Result<Uint8Array, StorageError>>;
168
- /** Write file contents */
169
- write(path: string, data: Uint8Array): Promise<Result<void, StorageError>>;
170
166
  /** Delete file */
171
167
  delete(path: string): Promise<Result<boolean, StorageError>>;
172
168
  /** Check if file exists */
173
169
  exists(path: string): Promise<Result<boolean, StorageError>>;
174
170
  /** List files in directory */
175
171
  list(prefix: string): Promise<Result<string[], StorageError>>;
172
+ /** Read file contents */
173
+ read(path: string): Promise<Result<Uint8Array, StorageError>>;
176
174
  /** Get file metadata (size, modified time) */
177
175
  stat(path: string): Promise<Result<{
178
176
  size: number;
179
177
  modifiedAt: Date;
180
178
  } | null, StorageError>>;
179
+ /** Write file contents */
180
+ write(path: string, data: Uint8Array): Promise<Result<void, StorageError>>;
181
181
  }
182
182
  export { IndexError, CacheError, AdapterAuthError, StorageError, SearchOptions, SearchResult, IndexStats, IndexAdapter, CacheAdapter, AuthAdapter, StorageAdapter };