@agentuity/core 0.0.33 → 0.0.36

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 (42) hide show
  1. package/dist/index.js +5 -0
  2. package/dist/index.js.map +1 -0
  3. package/dist/json.js +23 -0
  4. package/dist/json.js.map +1 -0
  5. package/dist/services/_util.js +107 -0
  6. package/dist/services/_util.js.map +1 -0
  7. package/dist/services/adapter.js +2 -0
  8. package/dist/services/adapter.js.map +1 -0
  9. package/dist/services/exception.js +8 -0
  10. package/dist/services/exception.js.map +1 -0
  11. package/dist/services/index.js +8 -0
  12. package/dist/services/index.js.map +1 -0
  13. package/dist/services/keyvalue.js +85 -0
  14. package/dist/services/keyvalue.js.map +1 -0
  15. package/dist/services/objectstore.js +218 -0
  16. package/dist/services/objectstore.js.map +1 -0
  17. package/dist/services/stream.js +392 -0
  18. package/dist/services/stream.js.map +1 -0
  19. package/dist/services/vector.js +242 -0
  20. package/dist/services/vector.js.map +1 -0
  21. package/dist/standard_schema.js +2 -0
  22. package/dist/standard_schema.js.map +1 -0
  23. package/dist/typehelper.js +2 -0
  24. package/dist/typehelper.js.map +1 -0
  25. package/package.json +5 -4
  26. package/src/index.ts +4 -0
  27. package/src/json.ts +26 -0
  28. package/src/services/__test__/keyvalue.test.ts +402 -0
  29. package/src/services/__test__/mock-adapter.ts +114 -0
  30. package/src/services/__test__/objectstore.test.ts +431 -0
  31. package/src/services/__test__/stream.test.ts +554 -0
  32. package/src/services/__test__/vector.test.ts +813 -0
  33. package/src/services/_util.ts +117 -0
  34. package/src/services/adapter.ts +33 -0
  35. package/src/services/exception.ts +7 -0
  36. package/src/services/index.ts +7 -0
  37. package/src/services/keyvalue.ts +185 -0
  38. package/src/services/objectstore.ts +466 -0
  39. package/src/services/stream.ts +614 -0
  40. package/src/services/vector.ts +599 -0
  41. package/src/standard_schema.ts +69 -0
  42. package/src/typehelper.ts +5 -0
@@ -0,0 +1,599 @@
1
+ import { FetchAdapter } from './adapter';
2
+ import { buildUrl, toServiceException } from './_util';
3
+ import { safeStringify } from '../json';
4
+
5
+ /**
6
+ * Base properties shared by all vector upsert operations
7
+ */
8
+ export interface VectorUpsertBase {
9
+ /**
10
+ * the key of the vector object which can be used as a reference. the value of this key is opaque to the vector storage.
11
+ */
12
+ key: string;
13
+
14
+ /**
15
+ * the metadata to upsert
16
+ */
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+
20
+ /**
21
+ * Upsert using pre-computed embeddings
22
+ */
23
+ export interface VectorUpsertEmbeddings extends VectorUpsertBase {
24
+ /**
25
+ * the embeddings to upsert
26
+ */
27
+ embeddings: Array<number>;
28
+ document?: never;
29
+ }
30
+
31
+ /**
32
+ * Upsert using text that will be converted to embeddings
33
+ */
34
+ export interface VectorUpsertText extends VectorUpsertBase {
35
+ /**
36
+ * the text to use for the embedding
37
+ */
38
+ document: string;
39
+ embeddings?: never;
40
+ }
41
+
42
+ /**
43
+ * Parameters for upserting a vector
44
+ */
45
+ export type VectorUpsertParams = VectorUpsertEmbeddings | VectorUpsertText;
46
+
47
+ /**
48
+ * Parameters for searching vectors
49
+ */
50
+ export interface VectorSearchParams<T extends Record<string, unknown> = Record<string, unknown>> {
51
+ /**
52
+ * The text query to search for in the vector storage. This will be converted to embeddings
53
+ * and used to find semantically similar documents.
54
+ *
55
+ * @example "comfortable office chair"
56
+ * @example "machine learning algorithms"
57
+ */
58
+ query: string;
59
+
60
+ /**
61
+ * Maximum number of search results to return. If not specified, the server default will be used.
62
+ * Must be a positive integer.
63
+ *
64
+ * @default 10
65
+ * @example 5
66
+ * @example 20
67
+ */
68
+ limit?: number;
69
+
70
+ /**
71
+ * Minimum similarity threshold for results. Only vectors with similarity scores greater than or equal
72
+ * to this value will be returned. Value must be between 0.0 and 1.0, where 1.0 means exact match
73
+ * and 0.0 means no similarity requirement.
74
+ *
75
+ * @minimum 0.0
76
+ * @maximum 1.0
77
+ * @example 0.7
78
+ * @example 0.5
79
+ */
80
+ similarity?: number;
81
+
82
+ /**
83
+ * Metadata filters to apply to the search. Only vectors whose metadata matches all specified
84
+ * key-value pairs will be included in results. Must be a valid JSON object if provided.
85
+ *
86
+ * @example { category: "furniture", inStock: true }
87
+ * @example { userId: "123", type: "product" }
88
+ */
89
+ metadata?: T;
90
+ }
91
+
92
+ /**
93
+ * Result of a vector search operation with optional type-safe metadata
94
+ */
95
+ export interface VectorSearchResult<T extends Record<string, unknown> = Record<string, unknown>> {
96
+ /**
97
+ * the unique id of the object in vector storage
98
+ */
99
+ id: string;
100
+
101
+ /**
102
+ * the key used when the vector object was added to vector storage
103
+ */
104
+ key: string;
105
+
106
+ /**
107
+ * the metadata of the vector object when it was stored
108
+ */
109
+ metadata?: T;
110
+
111
+ /**
112
+ * the distance of the vector object from the query from 0-1. The larger the number, the more similar the vector object is to the query.
113
+ */
114
+ similarity: number;
115
+ }
116
+
117
+ /**
118
+ * Extended search result that includes the document and embeddings
119
+ */
120
+ export interface VectorSearchResultWithDocument<
121
+ T extends Record<string, unknown> = Record<string, unknown>,
122
+ > extends VectorSearchResult<T> {
123
+ /**
124
+ * the document that was used to create the vector object
125
+ */
126
+ document?: string;
127
+
128
+ /**
129
+ * the embeddings of the vector object
130
+ */
131
+ embeddings?: Array<number>;
132
+ }
133
+
134
+ /**
135
+ * Result of a vector upsert operation
136
+ */
137
+ export interface VectorUpsertResult {
138
+ /**
139
+ * the key from the original upsert document
140
+ */
141
+ key: string;
142
+
143
+ /**
144
+ * the generated id for this vector in storage
145
+ */
146
+ id: string;
147
+ }
148
+
149
+ /**
150
+ * Result when a vector is found by key
151
+ */
152
+ export interface VectorResultFound<T extends Record<string, unknown> = Record<string, unknown>> {
153
+ /**
154
+ * the vector data
155
+ */
156
+ data: VectorSearchResultWithDocument<T>;
157
+
158
+ /**
159
+ * the vector was found
160
+ */
161
+ exists: true;
162
+ }
163
+
164
+ /**
165
+ * Result when a vector is not found by key
166
+ */
167
+ export interface VectorResultNotFound {
168
+ /**
169
+ * no data available
170
+ */
171
+ data: never;
172
+
173
+ /**
174
+ * the vector was not found
175
+ */
176
+ exists: false;
177
+ }
178
+
179
+ /**
180
+ * Result of a get operation
181
+ */
182
+ export type VectorResult<T extends Record<string, unknown> = Record<string, unknown>> =
183
+ | VectorResultFound<T>
184
+ | VectorResultNotFound;
185
+
186
+ /**
187
+ * Vector storage service for managing vector embeddings
188
+ */
189
+ export interface VectorStorage {
190
+ /**
191
+ * upsert a vector into the vector storage
192
+ *
193
+ * @param name - the name of the vector storage
194
+ * @param documents - the documents for the vector upsert
195
+ * @returns array of results with key-to-id mappings for the upserted vectors
196
+ */
197
+ upsert(name: string, ...documents: VectorUpsertParams[]): Promise<VectorUpsertResult[]>;
198
+
199
+ /**
200
+ * get a vector from the vector storage by key
201
+ *
202
+ * @param name - the name of the vector storage
203
+ * @param key - the key of the vector to get
204
+ * @returns VectorResult with exists field for type-safe checking
205
+ */
206
+ get<T extends Record<string, unknown> = Record<string, unknown>>(
207
+ name: string,
208
+ key: string
209
+ ): Promise<VectorResult<T>>;
210
+
211
+ /**
212
+ * get multiple vectors from the vector storage by keys
213
+ *
214
+ * @param name - the name of the vector storage
215
+ * @param keys - the keys of the vectors to get
216
+ * @returns a Map of key to vector data for found vectors
217
+ */
218
+ getMany<T extends Record<string, unknown> = Record<string, unknown>>(
219
+ name: string,
220
+ ...keys: string[]
221
+ ): Promise<Map<string, VectorSearchResultWithDocument<T>>>;
222
+
223
+ /**
224
+ * search for vectors in the vector storage
225
+ *
226
+ * @param name - the name of the vector storage
227
+ * @param params - the parameters for the vector search
228
+ * @returns the results of the vector search with type-safe metadata
229
+ */
230
+ search<T extends Record<string, unknown> = Record<string, unknown>>(
231
+ name: string,
232
+ params: VectorSearchParams<T>
233
+ ): Promise<VectorSearchResult<T>[]>;
234
+
235
+ /**
236
+ * delete vectors from the vector storage
237
+ *
238
+ * @param name - the name of the vector storage
239
+ * @param keys - the keys of the vectors to delete
240
+ * @returns the number of vector objects that were deleted
241
+ */
242
+ delete(name: string, ...keys: string[]): Promise<number>;
243
+
244
+ /**
245
+ * check if a vector storage exists
246
+ *
247
+ * @param name - the name of the vector storage
248
+ * @returns true if the storage exists, false otherwise
249
+ */
250
+ exists(name: string): Promise<boolean>;
251
+ }
252
+
253
+ interface VectorUpsertSuccessResponse {
254
+ success: true;
255
+ data: Array<{ id: string }>;
256
+ }
257
+
258
+ interface VectorUpsertErrorResponse {
259
+ success: false;
260
+ message: string;
261
+ }
262
+
263
+ type VectorUpsertResponse = VectorUpsertSuccessResponse | VectorUpsertErrorResponse;
264
+
265
+ interface VectorGetSuccessResponse {
266
+ success: true;
267
+ data: VectorSearchResultWithDocument | null;
268
+ }
269
+
270
+ interface VectorGetErrorResponse {
271
+ success: false;
272
+ message: string;
273
+ }
274
+
275
+ type VectorGetResponse = VectorGetSuccessResponse | VectorGetErrorResponse;
276
+
277
+ interface VectorSearchSuccessResponse {
278
+ success: true;
279
+ data: VectorSearchResult[];
280
+ }
281
+
282
+ interface VectorSearchErrorResponse {
283
+ success: false;
284
+ message: string;
285
+ }
286
+
287
+ type VectorSearchResponse = VectorSearchSuccessResponse | VectorSearchErrorResponse;
288
+
289
+ interface VectorDeleteSuccessResponse {
290
+ success: true;
291
+ data: number;
292
+ }
293
+
294
+ interface VectorDeleteErrorResponse {
295
+ success: false;
296
+ message: string;
297
+ }
298
+
299
+ type VectorDeleteResponse = VectorDeleteSuccessResponse | VectorDeleteErrorResponse;
300
+
301
+ export class VectorStorageService implements VectorStorage {
302
+ #adapter: FetchAdapter;
303
+ #baseUrl: string;
304
+
305
+ constructor(baseUrl: string, adapter: FetchAdapter) {
306
+ this.#adapter = adapter;
307
+ this.#baseUrl = baseUrl;
308
+ }
309
+
310
+ async upsert(name: string, ...documents: VectorUpsertParams[]): Promise<VectorUpsertResult[]> {
311
+ if (!name || typeof name !== 'string' || name.trim().length === 0) {
312
+ throw new Error('Vector storage name is required and must be a non-empty string');
313
+ }
314
+
315
+ if (!documents || documents.length === 0) {
316
+ throw new Error('At least one document is required for upsert');
317
+ }
318
+
319
+ for (const doc of documents) {
320
+ if (!doc.key || typeof doc.key !== 'string' || doc.key.trim().length === 0) {
321
+ throw new Error('Each document must have a non-empty key');
322
+ }
323
+
324
+ if (!('embeddings' in doc) && !('document' in doc)) {
325
+ throw new Error('Each document must have either embeddings or document text');
326
+ }
327
+
328
+ if ('embeddings' in doc && doc.embeddings) {
329
+ if (!Array.isArray(doc.embeddings) || doc.embeddings.length === 0) {
330
+ throw new Error('Embeddings must be a non-empty array of numbers');
331
+ }
332
+ }
333
+
334
+ if ('document' in doc && doc.document) {
335
+ if (typeof doc.document !== 'string' || doc.document.trim().length === 0) {
336
+ throw new Error('Document must be a non-empty string');
337
+ }
338
+ }
339
+ }
340
+
341
+ const url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}`);
342
+ const signal = AbortSignal.timeout(30_000);
343
+
344
+ const res = await this.#adapter.invoke<VectorUpsertResponse>(url, {
345
+ method: 'PUT',
346
+ body: safeStringify(documents),
347
+ contentType: 'application/json',
348
+ signal,
349
+ telemetry: {
350
+ name: 'agentuity.vector.upsert',
351
+ attributes: {
352
+ name,
353
+ count: String(documents.length),
354
+ },
355
+ },
356
+ });
357
+
358
+ if (res.ok) {
359
+ if (res.data.success) {
360
+ return res.data.data.map((o, index) => ({
361
+ key: documents[index].key,
362
+ id: o.id,
363
+ }));
364
+ }
365
+ if ('message' in res.data) {
366
+ throw new Error(res.data.message);
367
+ }
368
+ }
369
+
370
+ throw await toServiceException(res.response);
371
+ }
372
+
373
+ async get<T extends Record<string, unknown> = Record<string, unknown>>(
374
+ name: string,
375
+ key: string
376
+ ): Promise<VectorResult<T>> {
377
+ if (!name || typeof name !== 'string' || name.trim().length === 0) {
378
+ throw new Error('Vector storage name is required and must be a non-empty string');
379
+ }
380
+
381
+ if (!key || typeof key !== 'string' || key.trim().length === 0) {
382
+ throw new Error('Key is required and must be a non-empty string');
383
+ }
384
+
385
+ const url = buildUrl(
386
+ this.#baseUrl,
387
+ `/vector/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(key)}`
388
+ );
389
+ const signal = AbortSignal.timeout(10_000);
390
+
391
+ const res = await this.#adapter.invoke<VectorGetResponse>(url, {
392
+ method: 'GET',
393
+ signal,
394
+ telemetry: {
395
+ name: 'agentuity.vector.get',
396
+ attributes: {
397
+ name,
398
+ key,
399
+ },
400
+ },
401
+ });
402
+
403
+ if (res.response.status === 404) {
404
+ return { exists: false } as VectorResultNotFound;
405
+ }
406
+
407
+ if (res.ok) {
408
+ if (res.data.success) {
409
+ return {
410
+ data: res.data.data as VectorSearchResultWithDocument<T>,
411
+ exists: true,
412
+ };
413
+ }
414
+ if ('message' in res.data) {
415
+ throw new Error(res.data.message);
416
+ }
417
+ }
418
+
419
+ throw await toServiceException(res.response);
420
+ }
421
+
422
+ async getMany<T extends Record<string, unknown> = Record<string, unknown>>(
423
+ name: string,
424
+ ...keys: string[]
425
+ ): Promise<Map<string, VectorSearchResultWithDocument<T>>> {
426
+ if (!name || typeof name !== 'string' || name.trim().length === 0) {
427
+ throw new Error('Vector storage name is required and must be a non-empty string');
428
+ }
429
+
430
+ if (keys.length === 0) {
431
+ return new Map();
432
+ }
433
+
434
+ for (const key of keys) {
435
+ if (!key || typeof key !== 'string' || key.trim().length === 0) {
436
+ throw new Error('All keys must be non-empty strings');
437
+ }
438
+ }
439
+
440
+ const results = await Promise.all(keys.map((key) => this.get<T>(name, key)));
441
+
442
+ const resultMap = new Map<string, VectorSearchResultWithDocument<T>>();
443
+ results.forEach((result, index) => {
444
+ if (result.exists) {
445
+ resultMap.set(keys[index], result.data);
446
+ }
447
+ });
448
+
449
+ return resultMap;
450
+ }
451
+
452
+ async search<T extends Record<string, unknown> = Record<string, unknown>>(
453
+ name: string,
454
+ params: VectorSearchParams<T>
455
+ ): Promise<VectorSearchResult<T>[]> {
456
+ if (!name || typeof name !== 'string' || name.trim().length === 0) {
457
+ throw new Error('Vector storage name is required and must be a non-empty string');
458
+ }
459
+
460
+ if (!params.query || typeof params.query !== 'string' || params.query.trim().length === 0) {
461
+ throw new Error('Query is required and must be a non-empty string');
462
+ }
463
+
464
+ if (params.limit !== undefined) {
465
+ if (typeof params.limit !== 'number' || params.limit <= 0) {
466
+ throw new Error('Limit must be a positive number');
467
+ }
468
+ }
469
+
470
+ if (params.similarity !== undefined) {
471
+ if (
472
+ typeof params.similarity !== 'number' ||
473
+ params.similarity < 0 ||
474
+ params.similarity > 1
475
+ ) {
476
+ throw new Error('Similarity must be a number between 0.0 and 1.0');
477
+ }
478
+ }
479
+
480
+ if (params.metadata !== undefined) {
481
+ if (typeof params.metadata !== 'object' || params.metadata === null) {
482
+ throw new Error('Metadata must be a valid object');
483
+ }
484
+ }
485
+
486
+ const url = buildUrl(this.#baseUrl, `/vector/2025-03-17/search/${encodeURIComponent(name)}`);
487
+ const signal = AbortSignal.timeout(30_000);
488
+
489
+ const attributes: Record<string, string> = {
490
+ name,
491
+ query: params.query,
492
+ };
493
+ if (params.limit !== undefined) {
494
+ attributes.limit = String(params.limit);
495
+ }
496
+ if (params.similarity !== undefined) {
497
+ attributes.similarity = String(params.similarity);
498
+ }
499
+
500
+ const res = await this.#adapter.invoke<VectorSearchResponse>(url, {
501
+ method: 'POST',
502
+ body: safeStringify(params),
503
+ contentType: 'application/json',
504
+ signal,
505
+ telemetry: {
506
+ name: 'agentuity.vector.search',
507
+ attributes,
508
+ },
509
+ });
510
+
511
+ if (res.response.status === 404) {
512
+ return [];
513
+ }
514
+
515
+ if (res.ok) {
516
+ if (res.data.success) {
517
+ return res.data.data as VectorSearchResult<T>[];
518
+ }
519
+ if ('message' in res.data) {
520
+ throw new Error(res.data.message);
521
+ }
522
+ }
523
+
524
+ throw await toServiceException(res.response);
525
+ }
526
+
527
+ async delete(name: string, ...keys: string[]): Promise<number> {
528
+ if (!name || typeof name !== 'string' || name.trim().length === 0) {
529
+ throw new Error('Vector storage name is required and must be a non-empty string');
530
+ }
531
+
532
+ if (keys.length === 0) {
533
+ return 0;
534
+ }
535
+
536
+ for (const key of keys) {
537
+ if (!key || typeof key !== 'string' || key.trim().length === 0) {
538
+ throw new Error('All keys must be non-empty strings');
539
+ }
540
+ }
541
+
542
+ const signal = AbortSignal.timeout(30_000);
543
+ let url: string;
544
+ let body: string | undefined;
545
+
546
+ if (keys.length === 1) {
547
+ url = buildUrl(
548
+ this.#baseUrl,
549
+ `/vector/2025-03-17/${encodeURIComponent(name)}/${encodeURIComponent(keys[0])}`
550
+ );
551
+ } else {
552
+ url = buildUrl(this.#baseUrl, `/vector/2025-03-17/${encodeURIComponent(name)}`);
553
+ body = safeStringify({ keys });
554
+ }
555
+
556
+ const res = await this.#adapter.invoke<VectorDeleteResponse>(url, {
557
+ method: 'DELETE',
558
+ ...(body && { body, contentType: 'application/json' }),
559
+ signal,
560
+ telemetry: {
561
+ name: 'agentuity.vector.delete',
562
+ attributes: {
563
+ name,
564
+ count: String(keys.length),
565
+ },
566
+ },
567
+ });
568
+
569
+ if (res.ok) {
570
+ if (res.data.success) {
571
+ return res.data.data;
572
+ }
573
+ if ('message' in res.data) {
574
+ throw new Error(res.data.message);
575
+ }
576
+ }
577
+
578
+ throw await toServiceException(res.response);
579
+ }
580
+
581
+ async exists(name: string): Promise<boolean> {
582
+ if (!name || typeof name !== 'string' || name.trim().length === 0) {
583
+ throw new Error('Vector storage name is required and must be a non-empty string');
584
+ }
585
+
586
+ try {
587
+ await this.search(name, { query: '_exists_check_', limit: 1 });
588
+ return true;
589
+ } catch (error) {
590
+ if (error instanceof Error) {
591
+ const statusMatch = error.message.match(/(\d{3})/);
592
+ if (statusMatch && statusMatch[1] === '404') {
593
+ return false;
594
+ }
595
+ }
596
+ throw error;
597
+ }
598
+ }
599
+ }
@@ -0,0 +1,69 @@
1
+ /** The Standard Schema interface. */
2
+ export interface StandardSchemaV1<Input = unknown, Output = Input> {
3
+ /** The Standard Schema properties. */
4
+ readonly '~standard': StandardSchemaV1.Props<Input, Output>;
5
+ }
6
+
7
+ // eslint-disable-next-line @typescript-eslint/no-namespace
8
+ export declare namespace StandardSchemaV1 {
9
+ /** The Standard Schema properties interface. */
10
+ export interface Props<Input = unknown, Output = Input> {
11
+ /** The version number of the standard. */
12
+ readonly version: 1;
13
+ /** The vendor name of the schema library. */
14
+ readonly vendor: string;
15
+ /** Validates unknown input values. */
16
+ readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
17
+ /** Inferred types associated with the schema. */
18
+ readonly types?: Types<Input, Output> | undefined;
19
+ }
20
+
21
+ /** The result interface of the validate function. */
22
+ export type Result<Output> = SuccessResult<Output> | FailureResult;
23
+
24
+ /** The result interface if validation succeeds. */
25
+ export interface SuccessResult<Output> {
26
+ /** The typed output value. */
27
+ readonly value: Output;
28
+ /** The non-existent issues. */
29
+ readonly issues?: undefined;
30
+ }
31
+
32
+ /** The result interface if validation fails. */
33
+ export interface FailureResult {
34
+ /** The issues of failed validation. */
35
+ readonly issues: ReadonlyArray<Issue>;
36
+ }
37
+
38
+ /** The issue interface of the failure output. */
39
+ export interface Issue {
40
+ /** The error message of the issue. */
41
+ readonly message: string;
42
+ /** The path of the issue, if any. */
43
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
44
+ }
45
+
46
+ /** The path segment interface of the issue. */
47
+ export interface PathSegment {
48
+ /** The key representing a path segment. */
49
+ readonly key: PropertyKey;
50
+ }
51
+
52
+ /** The Standard Schema types interface. */
53
+ export interface Types<Input = unknown, Output = Input> {
54
+ /** The input type of the schema. */
55
+ readonly input: Input;
56
+ /** The output type of the schema. */
57
+ readonly output: Output;
58
+ }
59
+
60
+ /** Infers the input type of a Standard Schema. */
61
+ export type InferInput<Schema extends StandardSchemaV1> = NonNullable<
62
+ Schema['~standard']['types']
63
+ >['input'];
64
+
65
+ /** Infers the output type of a Standard Schema. */
66
+ export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<
67
+ Schema['~standard']['types']
68
+ >['output'];
69
+ }
@@ -0,0 +1,5 @@
1
+ import type { StandardSchemaV1 } from './standard_schema';
2
+
3
+ export type InferInput<T> = T extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<T> : never;
4
+
5
+ export type InferOutput<T> = T extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<T> : void;