@milaboratories/pl-client 2.10.2 → 2.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-client",
3
- "version": "2.10.2",
3
+ "version": "2.11.0",
4
4
  "engines": {
5
5
  "node": ">=20.3.0"
6
6
  },
@@ -20,26 +20,26 @@
20
20
  "./src/**/*"
21
21
  ],
22
22
  "dependencies": {
23
- "@grpc/grpc-js": "~1.13.1",
24
- "@protobuf-ts/grpc-transport": "2.9.6",
25
- "@protobuf-ts/runtime": "2.9.6",
26
- "@protobuf-ts/runtime-rpc": "2.9.6",
23
+ "@grpc/grpc-js": "~1.13.4",
24
+ "@protobuf-ts/grpc-transport": "2.11.0",
25
+ "@protobuf-ts/runtime": "2.11.0",
26
+ "@protobuf-ts/runtime-rpc": "2.11.0",
27
27
  "canonicalize": "~2.1.0",
28
28
  "denque": "^2.1.0",
29
29
  "lru-cache": "^11.1.0",
30
30
  "https-proxy-agent": "^7.0.6",
31
- "long": "^5.3.1",
32
- "undici": "~7.5.0",
31
+ "long": "^5.3.2",
32
+ "undici": "~7.10.0",
33
33
  "utility-types": "^3.11.0",
34
34
  "yaml": "^2.7.0",
35
- "@milaboratories/ts-helpers": "^1.3.3",
36
- "@milaboratories/pl-http": "^1.1.2"
35
+ "@milaboratories/pl-http": "^1.1.3",
36
+ "@milaboratories/ts-helpers": "^1.4.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "typescript": "~5.5.4",
40
40
  "vite": "^6.3.5",
41
41
  "@types/node": "~20.16.15",
42
- "@protobuf-ts/plugin": "2.9.6",
42
+ "@protobuf-ts/plugin": "2.11.0",
43
43
  "@types/http-proxy": "^1.17.16",
44
44
  "@types/jest": "^29.5.14",
45
45
  "jest": "^29.7.0",
package/src/core/final.ts CHANGED
@@ -71,6 +71,7 @@ export const DefaultFinalResourceDataPredicate: FinalResourceDataPredicate = (r)
71
71
  case 'json/resourceError':
72
72
  return r.type.version === '1';
73
73
  case 'json/object':
74
+ case 'json-gz/object':
74
75
  case 'json/string':
75
76
  case 'json/array':
76
77
  case 'json/number':
@@ -79,6 +80,7 @@ export const DefaultFinalResourceDataPredicate: FinalResourceDataPredicate = (r)
79
80
  case 'Frontend/FromFolder':
80
81
  case 'BObjectSpec':
81
82
  case 'Blob':
83
+ case 'Null':
82
84
  case 'binary':
83
85
  case 'LSProvider':
84
86
  return true;
@@ -92,6 +94,8 @@ export const DefaultFinalResourceDataPredicate: FinalResourceDataPredicate = (r)
92
94
  return readyAndHasAllOutputsFilled(r);
93
95
  } else if (r.type.name.startsWith('PColumnData/')) {
94
96
  return readyOrDuplicateOrError(r);
97
+ } else if (r.type.name.startsWith('StreamWorkdir/')) {
98
+ return readyOrDuplicateOrError(r);
95
99
  } else {
96
100
  // Unknonw resource type detected
97
101
  // Set used to log this message only once
package/src/core/stat.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type TxStat = {
2
2
  txCount: number;
3
+ timeMs: number;
3
4
 
4
5
  rootsCreated: number;
5
6
  structsCreated: number;
@@ -33,7 +34,9 @@ export type TxStat = {
33
34
  kvGetBytes: number;
34
35
  };
35
36
 
36
- export function initialTxStat(): TxStat {
37
+ export type TxStatWithoutTime = Omit<TxStat, 'timeMs'>;
38
+
39
+ export function initialTxStatWithoutTime(): TxStatWithoutTime {
37
40
  return {
38
41
  txCount: 0,
39
42
  rootsCreated: 0,
@@ -63,10 +66,17 @@ export function initialTxStat(): TxStat {
63
66
  kvGetBytes: 0,
64
67
  };
65
68
  }
69
+ export function initialTxStat(): TxStat {
70
+ return {
71
+ ...initialTxStatWithoutTime(),
72
+ timeMs: 0,
73
+ };
74
+ }
66
75
 
67
76
  export function addStat(a: TxStat, b: TxStat): TxStat {
68
77
  return {
69
78
  txCount: a.txCount + b.txCount,
79
+ timeMs: a.timeMs + b.timeMs,
70
80
  rootsCreated: a.rootsCreated + b.rootsCreated,
71
81
  structsCreated: a.structsCreated + b.structsCreated,
72
82
  structsCreatedDataBytes: a.structsCreatedDataBytes + b.structsCreatedDataBytes,
@@ -29,15 +29,16 @@ import { TxAPI_Open_Request_WritableTx } from '../proto/github.com/milaboratory/
29
29
  import type { NonUndefined } from 'utility-types';
30
30
  import { toBytes } from '../util/util';
31
31
  import { fieldTypeToProto, protoToField, protoToResource } from './type_conversion';
32
- import { deepFreeze, notEmpty } from '@milaboratories/ts-helpers';
32
+ import { canonicalJsonBytes, canonicalJsonGzBytes, deepFreeze, notEmpty } from '@milaboratories/ts-helpers';
33
33
  import { isNotFoundError } from './errors';
34
34
  import type { FinalResourceDataPredicate } from './final';
35
35
  import type { LRUCache } from 'lru-cache';
36
36
  import type { ResourceDataCacheRecord } from './cache';
37
37
  import type { TxStat } from './stat';
38
- import { initialTxStat } from './stat';
38
+ import { initialTxStatWithoutTime } from './stat';
39
39
  import type { ErrorResourceData } from './error_resource';
40
40
  import { ErrorResourceType } from './error_resource';
41
+ import { JsonGzObject, JsonObject } from '../helpers/pl';
41
42
 
42
43
  /** Reference to resource, used only within transaction */
43
44
  export interface ResourceRef {
@@ -168,7 +169,14 @@ export class PlTransaction {
168
169
 
169
170
  private globalTxIdWasAwaited: boolean = false;
170
171
 
171
- public readonly stat: TxStat = initialTxStat();
172
+ private readonly _startTime = Date.now();
173
+ private readonly _stat = initialTxStatWithoutTime();
174
+ public get stat(): TxStat {
175
+ return {
176
+ ...this._stat,
177
+ timeMs: Date.now() - this._startTime,
178
+ };
179
+ }
172
180
 
173
181
  constructor(
174
182
  private readonly ll: LLPlTransaction,
@@ -200,7 +208,7 @@ export class PlTransaction {
200
208
  });
201
209
 
202
210
  // Adding stats
203
- this.stat.txCount++;
211
+ this._stat.txCount++;
204
212
  }
205
213
 
206
214
  private async drainAndAwaitPendingOps(): Promise<void> {
@@ -380,7 +388,7 @@ export class PlTransaction {
380
388
  }
381
389
 
382
390
  public createRoot(type: ResourceType): ResourceRef {
383
- this.stat.rootsCreated++;
391
+ this._stat.rootsCreated++;
384
392
  return this.createResource(
385
393
  true,
386
394
  (localId) => ({ oneofKind: 'resourceCreateRoot', resourceCreateRoot: { type, id: localId } }),
@@ -389,8 +397,8 @@ export class PlTransaction {
389
397
  }
390
398
 
391
399
  public createStruct(type: ResourceType, data?: Uint8Array | string): ResourceRef {
392
- this.stat.structsCreated++;
393
- this.stat.structsCreatedDataBytes += data?.length ?? 0;
400
+ this._stat.structsCreated++;
401
+ this._stat.structsCreatedDataBytes += data?.length ?? 0;
394
402
  return this.createResource(
395
403
  false,
396
404
  (localId) => ({
@@ -406,8 +414,8 @@ export class PlTransaction {
406
414
  }
407
415
 
408
416
  public createEphemeral(type: ResourceType, data?: Uint8Array | string): ResourceRef {
409
- this.stat.ephemeralsCreated++;
410
- this.stat.ephemeralsCreatedDataBytes += data?.length ?? 0;
417
+ this._stat.ephemeralsCreated++;
418
+ this._stat.ephemeralsCreatedDataBytes += data?.length ?? 0;
411
419
  return this.createResource(
412
420
  false,
413
421
  (localId) => ({
@@ -427,8 +435,8 @@ export class PlTransaction {
427
435
  data: Uint8Array | string,
428
436
  errorIfExists: boolean = false,
429
437
  ): ResourceRef {
430
- this.stat.valuesCreated++;
431
- this.stat.valuesCreatedDataBytes += data?.length ?? 0;
438
+ this._stat.valuesCreated++;
439
+ this._stat.valuesCreatedDataBytes += data?.length ?? 0;
432
440
  return this.createResource(
433
441
  false,
434
442
  (localId) => ({
@@ -444,6 +452,16 @@ export class PlTransaction {
444
452
  );
445
453
  }
446
454
 
455
+ public createJsonValue(data: unknown): ResourceRef {
456
+ const jsonData = canonicalJsonBytes(data);
457
+ return this.createValue(JsonObject, jsonData, false);
458
+ }
459
+
460
+ public createJsonGzValue(data: unknown, minSizeToGzip: number | undefined = 16_384): ResourceRef {
461
+ const { data: jsonData, isGzipped } = canonicalJsonGzBytes(data, minSizeToGzip);
462
+ return this.createValue(isGzipped ? JsonGzObject : JsonObject, jsonData, false);
463
+ }
464
+
447
465
  public createError(message: string): ResourceRef {
448
466
  return this.createValue(ErrorResourceType, JSON.stringify({ message } satisfies ErrorResourceData));
449
467
  }
@@ -521,13 +539,13 @@ export class PlTransaction {
521
539
  const fromCache = this.sharedResourceDataCache.get(rId);
522
540
  if (fromCache && fromCache.cacheTxOpenTimestamp < this.txOpenTimestamp) {
523
541
  if (!loadFields) {
524
- this.stat.rGetDataCacheHits++;
525
- this.stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;
542
+ this._stat.rGetDataCacheHits++;
543
+ this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;
526
544
  return fromCache.basicData;
527
545
  } else if (fromCache.data) {
528
- this.stat.rGetDataCacheHits++;
529
- this.stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;
530
- this.stat.rGetDataCacheFields += fromCache.data.fields.length;
546
+ this._stat.rGetDataCacheHits++;
547
+ this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;
548
+ this._stat.rGetDataCacheFields += fromCache.data.fields.length;
531
549
  return fromCache.data;
532
550
  }
533
551
  }
@@ -541,9 +559,9 @@ export class PlTransaction {
541
559
  (r) => protoToResource(notEmpty(r.resourceGet.resource)),
542
560
  );
543
561
 
544
- this.stat.rGetDataNetRequests++;
545
- this.stat.rGetDataNetBytes += result.data?.length ?? 0;
546
- this.stat.rGetDataNetFields += result.fields.length;
562
+ this._stat.rGetDataNetRequests++;
563
+ this._stat.rGetDataNetBytes += result.data?.length ?? 0;
564
+ this._stat.rGetDataNetFields += result.fields.length;
547
565
 
548
566
  // we will cache only final resource data states
549
567
  // caching result even if we were ignore the cache
@@ -614,7 +632,7 @@ export class PlTransaction {
614
632
  * have their values, if inputs list is not locked.
615
633
  */
616
634
  public lockInputs(rId: AnyResourceRef): void {
617
- this.stat.inputsLocked++;
635
+ this._stat.inputsLocked++;
618
636
  this.sendVoidAsync({
619
637
  oneofKind: 'resourceLockInputs',
620
638
  resourceLockInputs: { resourceId: toResourceId(rId) },
@@ -626,7 +644,7 @@ export class PlTransaction {
626
644
  * This is required for resource to pass deduplication.
627
645
  */
628
646
  public lockOutputs(rId: AnyResourceRef): void {
629
- this.stat.outputsLocked++;
647
+ this._stat.outputsLocked++;
630
648
  this.sendVoidAsync({
631
649
  oneofKind: 'resourceLockOutputs',
632
650
  resourceLockOutputs: { resourceId: toResourceId(rId) },
@@ -650,7 +668,7 @@ export class PlTransaction {
650
668
  //
651
669
 
652
670
  public createField(fId: AnyFieldRef, fieldType: FieldType, value?: AnyRef): void {
653
- this.stat.fieldsCreated++;
671
+ this._stat.fieldsCreated++;
654
672
  this.sendVoidAsync({
655
673
  oneofKind: 'fieldCreate',
656
674
  fieldCreate: { type: fieldTypeToProto(fieldType), id: toFieldId(fId) },
@@ -669,7 +687,7 @@ export class PlTransaction {
669
687
  }
670
688
 
671
689
  public setField(fId: AnyFieldRef, ref: AnyRef): void {
672
- this.stat.fieldsSet++;
690
+ this._stat.fieldsSet++;
673
691
  if (isResource(ref))
674
692
  this.sendVoidAsync({
675
693
  oneofKind: 'fieldSet',
@@ -692,7 +710,7 @@ export class PlTransaction {
692
710
  }
693
711
 
694
712
  public setFieldError(fId: AnyFieldRef, ref: AnyResourceRef): void {
695
- this.stat.fieldsSet++;
713
+ this._stat.fieldsSet++;
696
714
  this.sendVoidAsync({
697
715
  oneofKind: 'fieldSetError',
698
716
  fieldSetError: { field: toFieldId(fId), errResourceId: toResourceId(ref) },
@@ -700,7 +718,7 @@ export class PlTransaction {
700
718
  }
701
719
 
702
720
  public async getField(fId: AnyFieldRef): Promise<FieldData> {
703
- this.stat.fieldsGet++;
721
+ this._stat.fieldsGet++;
704
722
  return await this.sendSingleAndParse(
705
723
  { oneofKind: 'fieldGet', fieldGet: { field: toFieldId(fId) } },
706
724
  (r) => protoToField(notEmpty(r.fieldGet.field)),
@@ -732,9 +750,9 @@ export class PlTransaction {
732
750
  (r) => r.map((e) => e.resourceKeyValueList.record!),
733
751
  );
734
752
 
735
- this.stat.kvListRequests++;
736
- this.stat.kvListEntries += result.length;
737
- for (const kv of result) this.stat.kvListBytes += kv.key.length + kv.value.length;
753
+ this._stat.kvListRequests++;
754
+ this._stat.kvListEntries += result.length;
755
+ for (const kv of result) this._stat.kvListBytes += kv.key.length + kv.value.length;
738
756
 
739
757
  return result;
740
758
  }
@@ -757,8 +775,8 @@ export class PlTransaction {
757
775
  }
758
776
 
759
777
  public setKValue(rId: AnyResourceRef, key: string, value: Uint8Array | string): void {
760
- this.stat.kvSetRequests++;
761
- this.stat.kvSetBytes++;
778
+ this._stat.kvSetRequests++;
779
+ this._stat.kvSetBytes++;
762
780
  this.sendVoidAsync({
763
781
  oneofKind: 'resourceKeyValueSet',
764
782
  resourceKeyValueSet: {
@@ -788,8 +806,8 @@ export class PlTransaction {
788
806
  (r) => r.resourceKeyValueGet.value,
789
807
  );
790
808
 
791
- this.stat.kvGetRequests++;
792
- this.stat.kvGetBytes += result.length;
809
+ this._stat.kvGetRequests++;
810
+ this._stat.kvGetBytes += result.length;
793
811
 
794
812
  return result;
795
813
  }
@@ -815,8 +833,8 @@ export class PlTransaction {
815
833
  r.resourceKeyValueGetIfExists.exists ? r.resourceKeyValueGetIfExists.value : undefined,
816
834
  );
817
835
 
818
- this.stat.kvGetRequests++;
819
- this.stat.kvGetBytes += result?.length ?? 0;
836
+ this._stat.kvGetRequests++;
837
+ this._stat.kvGetBytes += result?.length ?? 0;
820
838
 
821
839
  return result;
822
840
  }
package/src/helpers/pl.ts CHANGED
@@ -23,6 +23,7 @@ export const ValueTestResource = rt('ValueTest', '1');
23
23
  export const JsonString = rt('json/string', '1');
24
24
  export const JsonBool = rt('json/bool', '1');
25
25
  export const JsonObject = rt('json/object', '1');
26
+ export const JsonGzObject = rt('json-gz/object', '1');
26
27
  export const JsonArray = rt('json/array', '1');
27
28
  export const JsonNumber = rt('json/number', '1');
28
29
  export const JsonNull = rt('json/null', '1');