s3db.js 11.2.3 → 11.2.5
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/s3db-cli.js +588 -74
- package/dist/s3db.cjs.js +2472 -150
- package/dist/s3db.cjs.js.map +1 -1
- package/dist/s3db.es.js +2464 -151
- package/dist/s3db.es.js.map +1 -1
- package/package.json +2 -1
- package/src/behaviors/enforce-limits.js +28 -4
- package/src/behaviors/index.js +6 -1
- package/src/client.class.js +11 -1
- package/src/concerns/base62.js +70 -0
- package/src/concerns/partition-queue.js +7 -1
- package/src/concerns/plugin-storage.js +75 -13
- package/src/database.class.js +19 -4
- package/src/errors.js +306 -27
- package/src/partition-drivers/base-partition-driver.js +12 -2
- package/src/partition-drivers/index.js +7 -1
- package/src/partition-drivers/memory-partition-driver.js +20 -5
- package/src/partition-drivers/sqs-partition-driver.js +6 -1
- package/src/plugins/audit.errors.js +46 -0
- package/src/plugins/backup/base-backup-driver.class.js +36 -6
- package/src/plugins/backup/filesystem-backup-driver.class.js +55 -7
- package/src/plugins/backup/index.js +40 -9
- package/src/plugins/backup/multi-backup-driver.class.js +69 -9
- package/src/plugins/backup/s3-backup-driver.class.js +48 -6
- package/src/plugins/backup.errors.js +45 -0
- package/src/plugins/cache/cache.class.js +8 -1
- package/src/plugins/cache.errors.js +47 -0
- package/src/plugins/cache.plugin.js +8 -1
- package/src/plugins/fulltext.errors.js +46 -0
- package/src/plugins/fulltext.plugin.js +15 -3
- package/src/plugins/index.js +1 -0
- package/src/plugins/metrics.errors.js +46 -0
- package/src/plugins/queue-consumer.plugin.js +31 -4
- package/src/plugins/queue.errors.js +46 -0
- package/src/plugins/replicator.errors.js +46 -0
- package/src/plugins/replicator.plugin.js +40 -5
- package/src/plugins/replicators/base-replicator.class.js +19 -3
- package/src/plugins/replicators/index.js +9 -3
- package/src/plugins/replicators/s3db-replicator.class.js +38 -8
- package/src/plugins/scheduler.errors.js +46 -0
- package/src/plugins/scheduler.plugin.js +79 -19
- package/src/plugins/state-machine.errors.js +47 -0
- package/src/plugins/state-machine.plugin.js +86 -17
- package/src/plugins/vector/distances.js +173 -0
- package/src/plugins/vector/kmeans.js +367 -0
- package/src/plugins/vector/metrics.js +369 -0
- package/src/plugins/vector/vector-error.js +43 -0
- package/src/plugins/vector.plugin.js +687 -0
- package/src/schema.class.js +232 -41
- package/src/stream/index.js +6 -1
- package/src/stream/resource-reader.class.js +6 -1
- package/src/validator.class.js +8 -0
package/src/schema.class.js
CHANGED
|
@@ -15,7 +15,7 @@ import { encrypt, decrypt } from "./concerns/crypto.js";
|
|
|
15
15
|
import { ValidatorManager } from "./validator.class.js";
|
|
16
16
|
import { tryFn, tryFnSync } from "./concerns/try-fn.js";
|
|
17
17
|
import { SchemaError } from "./errors.js";
|
|
18
|
-
import { encode as toBase62, decode as fromBase62, encodeDecimal, decodeDecimal } from "./concerns/base62.js";
|
|
18
|
+
import { encode as toBase62, decode as fromBase62, encodeDecimal, decodeDecimal, encodeFixedPoint, decodeFixedPoint } from "./concerns/base62.js";
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Generate base62 mapping for attributes
|
|
@@ -274,6 +274,60 @@ export const SchemaActions = {
|
|
|
274
274
|
return NaN;
|
|
275
275
|
});
|
|
276
276
|
},
|
|
277
|
+
fromArrayOfEmbeddings: (value, { separator, precision = 6 }) => {
|
|
278
|
+
if (value === null || value === undefined || !Array.isArray(value)) {
|
|
279
|
+
return value;
|
|
280
|
+
}
|
|
281
|
+
if (value.length === 0) {
|
|
282
|
+
return '';
|
|
283
|
+
}
|
|
284
|
+
const encodedItems = value.map(item => {
|
|
285
|
+
if (typeof item === 'number' && !isNaN(item)) {
|
|
286
|
+
return encodeFixedPoint(item, precision);
|
|
287
|
+
}
|
|
288
|
+
// fallback: try to parse as number, else keep as is
|
|
289
|
+
const n = Number(item);
|
|
290
|
+
return isNaN(n) ? '' : encodeFixedPoint(n, precision);
|
|
291
|
+
});
|
|
292
|
+
return encodedItems.join(separator);
|
|
293
|
+
},
|
|
294
|
+
toArrayOfEmbeddings: (value, { separator, precision = 6 }) => {
|
|
295
|
+
if (Array.isArray(value)) {
|
|
296
|
+
return value.map(v => (typeof v === 'number' ? v : decodeFixedPoint(v, precision)));
|
|
297
|
+
}
|
|
298
|
+
if (value === null || value === undefined) {
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
if (value === '') {
|
|
302
|
+
return [];
|
|
303
|
+
}
|
|
304
|
+
const str = String(value);
|
|
305
|
+
const items = [];
|
|
306
|
+
let current = '';
|
|
307
|
+
let i = 0;
|
|
308
|
+
while (i < str.length) {
|
|
309
|
+
if (str[i] === '\\' && i + 1 < str.length) {
|
|
310
|
+
current += str[i + 1];
|
|
311
|
+
i += 2;
|
|
312
|
+
} else if (str[i] === separator) {
|
|
313
|
+
items.push(current);
|
|
314
|
+
current = '';
|
|
315
|
+
i++;
|
|
316
|
+
} else {
|
|
317
|
+
current += str[i];
|
|
318
|
+
i++;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
items.push(current);
|
|
322
|
+
return items.map(v => {
|
|
323
|
+
if (typeof v === 'number') return v;
|
|
324
|
+
if (typeof v === 'string' && v !== '') {
|
|
325
|
+
const n = decodeFixedPoint(v, precision);
|
|
326
|
+
return isNaN(n) ? NaN : n;
|
|
327
|
+
}
|
|
328
|
+
return NaN;
|
|
329
|
+
});
|
|
330
|
+
},
|
|
277
331
|
|
|
278
332
|
}
|
|
279
333
|
|
|
@@ -351,16 +405,16 @@ export class Schema {
|
|
|
351
405
|
|
|
352
406
|
extractObjectKeys(obj, prefix = '') {
|
|
353
407
|
const objectKeys = [];
|
|
354
|
-
|
|
408
|
+
|
|
355
409
|
for (const [key, value] of Object.entries(obj)) {
|
|
356
410
|
if (key.startsWith('$$')) continue; // Skip schema metadata
|
|
357
|
-
|
|
411
|
+
|
|
358
412
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
359
|
-
|
|
413
|
+
|
|
360
414
|
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
361
415
|
// This is an object, add its key
|
|
362
416
|
objectKeys.push(fullKey);
|
|
363
|
-
|
|
417
|
+
|
|
364
418
|
// Check if it has nested objects
|
|
365
419
|
if (value.$$type === 'object') {
|
|
366
420
|
// Recursively extract nested object keys
|
|
@@ -368,31 +422,137 @@ export class Schema {
|
|
|
368
422
|
}
|
|
369
423
|
}
|
|
370
424
|
}
|
|
371
|
-
|
|
425
|
+
|
|
372
426
|
return objectKeys;
|
|
373
427
|
}
|
|
374
428
|
|
|
429
|
+
_generateHooksFromOriginalAttributes(attributes, prefix = '') {
|
|
430
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
431
|
+
if (key.startsWith('$$')) continue;
|
|
432
|
+
|
|
433
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
434
|
+
|
|
435
|
+
// Check if this is an object notation type definition (has 'type' property)
|
|
436
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value) && value.type) {
|
|
437
|
+
if (value.type === 'array' && value.items) {
|
|
438
|
+
// Handle array with object notation
|
|
439
|
+
const itemsType = value.items;
|
|
440
|
+
const arrayLength = typeof value.length === 'number' ? value.length : null;
|
|
441
|
+
|
|
442
|
+
if (itemsType === 'string' || (typeof itemsType === 'string' && itemsType.includes('string'))) {
|
|
443
|
+
this.addHook("beforeMap", fullKey, "fromArray");
|
|
444
|
+
this.addHook("afterUnmap", fullKey, "toArray");
|
|
445
|
+
} else if (itemsType === 'number' || (typeof itemsType === 'string' && itemsType.includes('number'))) {
|
|
446
|
+
const isIntegerArray = typeof itemsType === 'string' && itemsType.includes('integer');
|
|
447
|
+
const isEmbedding = !isIntegerArray && arrayLength !== null && arrayLength >= 256;
|
|
448
|
+
|
|
449
|
+
if (isIntegerArray) {
|
|
450
|
+
this.addHook("beforeMap", fullKey, "fromArrayOfNumbers");
|
|
451
|
+
this.addHook("afterUnmap", fullKey, "toArrayOfNumbers");
|
|
452
|
+
} else if (isEmbedding) {
|
|
453
|
+
this.addHook("beforeMap", fullKey, "fromArrayOfEmbeddings");
|
|
454
|
+
this.addHook("afterUnmap", fullKey, "toArrayOfEmbeddings");
|
|
455
|
+
} else {
|
|
456
|
+
this.addHook("beforeMap", fullKey, "fromArrayOfDecimals");
|
|
457
|
+
this.addHook("afterUnmap", fullKey, "toArrayOfDecimals");
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
// For other types with object notation, they'll be handled by the flattened processing
|
|
462
|
+
} else if (typeof value === 'object' && value !== null && !Array.isArray(value) && !value.type) {
|
|
463
|
+
// This is a nested object, recurse
|
|
464
|
+
this._generateHooksFromOriginalAttributes(value, fullKey);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
375
469
|
generateAutoHooks() {
|
|
470
|
+
// First, process the original attributes to find arrays with object notation
|
|
471
|
+
// This handles cases like: { type: 'array', items: 'number', length: 768 }
|
|
472
|
+
this._generateHooksFromOriginalAttributes(this.attributes);
|
|
473
|
+
|
|
474
|
+
// Then process the flattened schema for other types
|
|
376
475
|
const schema = flatten(cloneDeep(this.attributes), { safe: true });
|
|
377
476
|
|
|
378
477
|
for (const [name, definition] of Object.entries(schema)) {
|
|
379
|
-
//
|
|
380
|
-
if (
|
|
381
|
-
|
|
478
|
+
// Skip metadata fields
|
|
479
|
+
if (name.includes('$$')) continue;
|
|
480
|
+
|
|
481
|
+
// Skip if hooks already exist (from object notation processing)
|
|
482
|
+
if (this.options.hooks.beforeMap[name] || this.options.hooks.afterUnmap[name]) {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Normalize definition - can be a string or value from flattened object
|
|
487
|
+
const defStr = typeof definition === 'string' ? definition : '';
|
|
488
|
+
const defType = typeof definition === 'object' && definition !== null ? definition.type : null;
|
|
489
|
+
|
|
490
|
+
// Check if this is an embedding type (custom shorthand)
|
|
491
|
+
const isEmbeddingType = defStr.includes("embedding") || defType === 'embedding';
|
|
492
|
+
|
|
493
|
+
if (isEmbeddingType) {
|
|
494
|
+
// Extract length from embedding:1536 or embedding|length:1536
|
|
495
|
+
let embeddingLength = null;
|
|
496
|
+
const lengthMatch = defStr.match(/embedding:(\d+)/);
|
|
497
|
+
if (lengthMatch) {
|
|
498
|
+
embeddingLength = parseInt(lengthMatch[1], 10);
|
|
499
|
+
} else if (defStr.includes('length:')) {
|
|
500
|
+
const match = defStr.match(/length:(\d+)/);
|
|
501
|
+
if (match) embeddingLength = parseInt(match[1], 10);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Embeddings always use fixed-point encoding
|
|
505
|
+
this.addHook("beforeMap", name, "fromArrayOfEmbeddings");
|
|
506
|
+
this.addHook("afterUnmap", name, "toArrayOfEmbeddings");
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Check if this is an array type
|
|
511
|
+
const isArray = defStr.includes("array") || defType === 'array';
|
|
512
|
+
|
|
513
|
+
if (isArray) {
|
|
514
|
+
// Determine item type for arrays
|
|
515
|
+
let itemsType = null;
|
|
516
|
+
if (typeof definition === 'object' && definition !== null && definition.items) {
|
|
517
|
+
itemsType = definition.items;
|
|
518
|
+
} else if (defStr.includes('items:string')) {
|
|
519
|
+
itemsType = 'string';
|
|
520
|
+
} else if (defStr.includes('items:number')) {
|
|
521
|
+
itemsType = 'number';
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (itemsType === 'string' || (typeof itemsType === 'string' && itemsType.includes('string'))) {
|
|
382
525
|
this.addHook("beforeMap", name, "fromArray");
|
|
383
526
|
this.addHook("afterUnmap", name, "toArray");
|
|
384
|
-
} else if (
|
|
527
|
+
} else if (itemsType === 'number' || (typeof itemsType === 'string' && itemsType.includes('number'))) {
|
|
385
528
|
// Check if the array items should be treated as integers
|
|
386
|
-
const isIntegerArray =
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
529
|
+
const isIntegerArray = defStr.includes("integer:true") ||
|
|
530
|
+
defStr.includes("|integer:") ||
|
|
531
|
+
defStr.includes("|integer") ||
|
|
532
|
+
(typeof itemsType === 'string' && itemsType.includes('integer'));
|
|
533
|
+
|
|
534
|
+
// Check if this is an embedding array (large arrays of decimals)
|
|
535
|
+
// Common embedding dimensions: 256, 384, 512, 768, 1024, 1536, 2048, 3072
|
|
536
|
+
let arrayLength = null;
|
|
537
|
+
if (typeof definition === 'object' && definition !== null && typeof definition.length === 'number') {
|
|
538
|
+
arrayLength = definition.length;
|
|
539
|
+
} else if (defStr.includes('length:')) {
|
|
540
|
+
const match = defStr.match(/length:(\d+)/);
|
|
541
|
+
if (match) arrayLength = parseInt(match[1], 10);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const isEmbedding = !isIntegerArray && arrayLength !== null && arrayLength >= 256;
|
|
545
|
+
|
|
390
546
|
if (isIntegerArray) {
|
|
391
547
|
// Use standard base62 for arrays of integers
|
|
392
548
|
this.addHook("beforeMap", name, "fromArrayOfNumbers");
|
|
393
549
|
this.addHook("afterUnmap", name, "toArrayOfNumbers");
|
|
550
|
+
} else if (isEmbedding) {
|
|
551
|
+
// Use fixed-point encoding for embedding vectors (77% compression)
|
|
552
|
+
this.addHook("beforeMap", name, "fromArrayOfEmbeddings");
|
|
553
|
+
this.addHook("afterUnmap", name, "toArrayOfEmbeddings");
|
|
394
554
|
} else {
|
|
395
|
-
// Use decimal-aware base62 for arrays of decimals
|
|
555
|
+
// Use decimal-aware base62 for regular arrays of decimals
|
|
396
556
|
this.addHook("beforeMap", name, "fromArrayOfDecimals");
|
|
397
557
|
this.addHook("afterUnmap", name, "toArrayOfDecimals");
|
|
398
558
|
}
|
|
@@ -402,7 +562,7 @@ export class Schema {
|
|
|
402
562
|
}
|
|
403
563
|
|
|
404
564
|
// Handle secrets
|
|
405
|
-
if (
|
|
565
|
+
if (defStr.includes("secret") || defType === 'secret') {
|
|
406
566
|
if (this.options.autoEncrypt) {
|
|
407
567
|
this.addHook("beforeMap", name, "encrypt");
|
|
408
568
|
}
|
|
@@ -414,12 +574,12 @@ export class Schema {
|
|
|
414
574
|
}
|
|
415
575
|
|
|
416
576
|
// Handle numbers (only for non-array fields)
|
|
417
|
-
if (
|
|
577
|
+
if (defStr.includes("number") || defType === 'number') {
|
|
418
578
|
// Check if it's specifically an integer field
|
|
419
|
-
const isInteger =
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
579
|
+
const isInteger = defStr.includes("integer:true") ||
|
|
580
|
+
defStr.includes("|integer:") ||
|
|
581
|
+
defStr.includes("|integer");
|
|
582
|
+
|
|
423
583
|
if (isInteger) {
|
|
424
584
|
// Use standard base62 for integers
|
|
425
585
|
this.addHook("beforeMap", name, "toBase62");
|
|
@@ -433,21 +593,21 @@ export class Schema {
|
|
|
433
593
|
}
|
|
434
594
|
|
|
435
595
|
// Handle booleans
|
|
436
|
-
if (
|
|
596
|
+
if (defStr.includes("boolean") || defType === 'boolean') {
|
|
437
597
|
this.addHook("beforeMap", name, "fromBool");
|
|
438
598
|
this.addHook("afterUnmap", name, "toBool");
|
|
439
599
|
continue;
|
|
440
600
|
}
|
|
441
601
|
|
|
442
602
|
// Handle JSON fields
|
|
443
|
-
if (
|
|
603
|
+
if (defStr.includes("json") || defType === 'json') {
|
|
444
604
|
this.addHook("beforeMap", name, "toJSON");
|
|
445
605
|
this.addHook("afterUnmap", name, "fromJSON");
|
|
446
606
|
continue;
|
|
447
607
|
}
|
|
448
608
|
|
|
449
609
|
// Handle object fields - add JSON serialization hooks
|
|
450
|
-
if (definition === "object" ||
|
|
610
|
+
if (definition === "object" || defStr.includes("object") || defType === 'object') {
|
|
451
611
|
this.addHook("beforeMap", name, "toJSON");
|
|
452
612
|
this.addHook("afterUnmap", name, "fromJSON");
|
|
453
613
|
continue;
|
|
@@ -604,8 +764,11 @@ export class Schema {
|
|
|
604
764
|
const originalKey = reversedMap && reversedMap[key] ? reversedMap[key] : key;
|
|
605
765
|
let parsedValue = value;
|
|
606
766
|
const attrDef = this.getAttributeDefinition(originalKey);
|
|
767
|
+
const hasAfterUnmapHook = this.options.hooks?.afterUnmap?.[originalKey];
|
|
768
|
+
|
|
607
769
|
// Always unmap base62 strings to numbers for number fields (but not array fields or decimal fields)
|
|
608
|
-
|
|
770
|
+
// Skip if there are afterUnmap hooks that will handle the conversion
|
|
771
|
+
if (!hasAfterUnmapHook && typeof attrDef === 'string' && attrDef.includes('number') && !attrDef.includes('array') && !attrDef.includes('decimal')) {
|
|
609
772
|
if (typeof parsedValue === 'string' && parsedValue !== '') {
|
|
610
773
|
parsedValue = fromBase62(parsedValue);
|
|
611
774
|
} else if (typeof parsedValue === 'number') {
|
|
@@ -677,28 +840,56 @@ export class Schema {
|
|
|
677
840
|
*/
|
|
678
841
|
preprocessAttributesForValidation(attributes) {
|
|
679
842
|
const processed = {};
|
|
680
|
-
|
|
843
|
+
|
|
681
844
|
for (const [key, value] of Object.entries(attributes)) {
|
|
682
|
-
if (typeof value === '
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
}
|
|
694
|
-
|
|
845
|
+
if (typeof value === 'string') {
|
|
846
|
+
// Expand embedding:XXX shorthand to array|items:number|length:XXX
|
|
847
|
+
if (value.startsWith('embedding:')) {
|
|
848
|
+
const lengthMatch = value.match(/embedding:(\d+)/);
|
|
849
|
+
if (lengthMatch) {
|
|
850
|
+
const length = lengthMatch[1];
|
|
851
|
+
// Extract any additional modifiers after the length
|
|
852
|
+
const rest = value.substring(`embedding:${length}`.length);
|
|
853
|
+
processed[key] = `array|items:number|length:${length}|empty:false${rest}`;
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
// Expand embedding|... to array|items:number|...
|
|
858
|
+
if (value.startsWith('embedding|') || value === 'embedding') {
|
|
859
|
+
processed[key] = value.replace(/^embedding/, 'array|items:number|empty:false');
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
processed[key] = value;
|
|
863
|
+
} else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
864
|
+
// Check if this is a validator type definition (has 'type' property that is NOT '$$type')
|
|
865
|
+
// vs a nested object structure
|
|
866
|
+
const hasValidatorType = value.type !== undefined && key !== '$$type';
|
|
867
|
+
|
|
868
|
+
if (hasValidatorType) {
|
|
869
|
+
// This is a validator type definition (e.g., { type: 'array', items: 'number' }), pass it through
|
|
870
|
+
processed[key] = value;
|
|
871
|
+
} else {
|
|
872
|
+
// This is a nested object structure, wrap it for validation
|
|
873
|
+
const isExplicitRequired = value.$$type && value.$$type.includes('required');
|
|
874
|
+
const isExplicitOptional = value.$$type && value.$$type.includes('optional');
|
|
875
|
+
const objectConfig = {
|
|
876
|
+
type: 'object',
|
|
877
|
+
properties: this.preprocessAttributesForValidation(value),
|
|
878
|
+
strict: false
|
|
879
|
+
};
|
|
880
|
+
// If explicitly required, don't mark as optional
|
|
881
|
+
if (isExplicitRequired) {
|
|
882
|
+
// nothing
|
|
883
|
+
} else if (isExplicitOptional || this.allNestedObjectsOptional) {
|
|
884
|
+
objectConfig.optional = true;
|
|
885
|
+
}
|
|
886
|
+
processed[key] = objectConfig;
|
|
695
887
|
}
|
|
696
|
-
processed[key] = objectConfig;
|
|
697
888
|
} else {
|
|
698
889
|
processed[key] = value;
|
|
699
890
|
}
|
|
700
891
|
}
|
|
701
|
-
|
|
892
|
+
|
|
702
893
|
return processed;
|
|
703
894
|
}
|
|
704
895
|
}
|
package/src/stream/index.js
CHANGED
|
@@ -3,10 +3,15 @@ export * from "./resource-writer.class.js"
|
|
|
3
3
|
export * from "./resource-ids-reader.class.js"
|
|
4
4
|
export * from "./resource-ids-page-reader.class.js"
|
|
5
5
|
|
|
6
|
+
import { StreamError } from '../errors.js';
|
|
7
|
+
|
|
6
8
|
export function streamToString(stream) {
|
|
7
9
|
return new Promise((resolve, reject) => {
|
|
8
10
|
if (!stream) {
|
|
9
|
-
return reject(new
|
|
11
|
+
return reject(new StreamError('Stream is undefined', {
|
|
12
|
+
operation: 'streamToString',
|
|
13
|
+
suggestion: 'Ensure a valid stream is passed to streamToString()'
|
|
14
|
+
}));
|
|
10
15
|
}
|
|
11
16
|
const chunks = [];
|
|
12
17
|
stream.on('data', (chunk) => chunks.push(chunk));
|
|
@@ -4,13 +4,18 @@ import { PromisePool } from "@supercharge/promise-pool";
|
|
|
4
4
|
|
|
5
5
|
import { ResourceIdsPageReader } from "./resource-ids-page-reader.class.js"
|
|
6
6
|
import tryFn from "../concerns/try-fn.js";
|
|
7
|
+
import { StreamError } from '../errors.js';
|
|
7
8
|
|
|
8
9
|
export class ResourceReader extends EventEmitter {
|
|
9
10
|
constructor({ resource, batchSize = 10, concurrency = 5 }) {
|
|
10
11
|
super()
|
|
11
12
|
|
|
12
13
|
if (!resource) {
|
|
13
|
-
throw new
|
|
14
|
+
throw new StreamError('Resource is required for ResourceReader', {
|
|
15
|
+
operation: 'constructor',
|
|
16
|
+
resource: resource?.name,
|
|
17
|
+
suggestion: 'Pass a valid Resource instance when creating ResourceReader'
|
|
18
|
+
});
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
this.resource = resource;
|
package/src/validator.class.js
CHANGED
|
@@ -82,6 +82,14 @@ export class Validator extends FastestValidator {
|
|
|
82
82
|
type: "any",
|
|
83
83
|
custom: this.autoEncrypt ? jsonHandler : undefined,
|
|
84
84
|
})
|
|
85
|
+
|
|
86
|
+
// Embedding type - shorthand for arrays of numbers optimized for embeddings
|
|
87
|
+
// Usage: 'embedding:1536' or 'embedding|length:768'
|
|
88
|
+
this.alias('embedding', {
|
|
89
|
+
type: "array",
|
|
90
|
+
items: "number",
|
|
91
|
+
empty: false,
|
|
92
|
+
})
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
95
|
|