@milaboratories/pl-client 2.10.2 → 2.11.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.
- package/dist/core/driver.d.ts +2 -2
- package/dist/core/driver.d.ts.map +1 -1
- package/dist/core/final.d.ts.map +1 -1
- package/dist/core/grpc.d.ts +16 -0
- package/dist/core/grpc.d.ts.map +1 -0
- package/dist/core/ll_client.d.ts +11 -3
- package/dist/core/ll_client.d.ts.map +1 -1
- package/dist/core/stat.d.ts +3 -0
- package/dist/core/stat.d.ts.map +1 -1
- package/dist/core/transaction.d.ts +5 -1
- package/dist/core/transaction.d.ts.map +1 -1
- package/dist/helpers/pl.d.ts +1 -0
- package/dist/helpers/pl.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1113 -1056
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
- package/src/core/client.test.ts +2 -2
- package/src/core/client.ts +3 -3
- package/src/core/driver.ts +2 -2
- package/src/core/final.ts +4 -0
- package/src/core/grpc.ts +17 -0
- package/src/core/ll_client.ts +65 -9
- package/src/core/stat.ts +11 -1
- package/src/core/transaction.ts +52 -34
- package/src/core/unauth_client.ts +3 -3
- package/src/helpers/pl.ts +1 -0
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.1",
|
|
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.
|
|
24
|
-
"@protobuf-ts/grpc-transport": "2.
|
|
25
|
-
"@protobuf-ts/runtime": "2.
|
|
26
|
-
"@protobuf-ts/runtime-rpc": "2.
|
|
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.
|
|
32
|
-
"undici": "~7.
|
|
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/
|
|
36
|
-
"@milaboratories/
|
|
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.
|
|
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/client.test.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getTestClient, getTestClientConf } from '../test/test_config';
|
|
2
2
|
import { PlClient } from './client';
|
|
3
3
|
import { PlDriver, PlDriverDefinition } from './driver';
|
|
4
|
-
import { GrpcTransport } from '@protobuf-ts/grpc-transport';
|
|
5
4
|
import { Dispatcher, request } from 'undici';
|
|
5
|
+
import { GrpcClientProviderFactory } from './grpc';
|
|
6
6
|
|
|
7
7
|
test('test client init', async () => {
|
|
8
8
|
const client = await getTestClient(undefined);
|
|
@@ -27,7 +27,7 @@ interface SimpleDriver extends PlDriver {
|
|
|
27
27
|
|
|
28
28
|
const SimpleDriverDefinition: PlDriverDefinition<SimpleDriver> = {
|
|
29
29
|
name: 'SimpleDriver',
|
|
30
|
-
init(pl: PlClient,
|
|
30
|
+
init(pl: PlClient, grpcClientProviderFactory: GrpcClientProviderFactory, httpDispatcher: Dispatcher): SimpleDriver {
|
|
31
31
|
return {
|
|
32
32
|
async ping(): Promise<string> {
|
|
33
33
|
const response = await request('https://cdn.milaboratory.com/ping', {
|
package/src/core/client.ts
CHANGED
|
@@ -142,7 +142,7 @@ export class PlClient {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
public async ping(): Promise<MaintenanceAPI_Ping_Response> {
|
|
145
|
-
return (await this._ll.grpcPl.ping({})).response;
|
|
145
|
+
return (await this._ll.grpcPl.get().ping({})).response;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
public get conf(): PlClientConfig {
|
|
@@ -296,7 +296,7 @@ export class PlClient {
|
|
|
296
296
|
if (ok) {
|
|
297
297
|
// syncing on transaction if requested
|
|
298
298
|
if (ops?.sync === undefined ? this.forceSync : ops?.sync)
|
|
299
|
-
await this._ll.grpcPl.txSync({ txId });
|
|
299
|
+
await this._ll.grpcPl.get().txSync({ txId });
|
|
300
300
|
|
|
301
301
|
// introducing artificial delay, if requested
|
|
302
302
|
if (writable && this.txDelay > 0)
|
|
@@ -342,7 +342,7 @@ export class PlClient {
|
|
|
342
342
|
public getDriver<Drv extends PlDriver>(definition: PlDriverDefinition<Drv>): Drv {
|
|
343
343
|
const attached = this.drivers.get(definition.name);
|
|
344
344
|
if (attached !== undefined) return attached as Drv;
|
|
345
|
-
const driver = definition.init(this, this.
|
|
345
|
+
const driver = definition.init(this, this._ll, this.httpDispatcher);
|
|
346
346
|
this.drivers.set(definition.name, driver);
|
|
347
347
|
return driver;
|
|
348
348
|
}
|
package/src/core/driver.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { PlClient } from './client';
|
|
2
|
-
import type { GrpcTransport } from '@protobuf-ts/grpc-transport';
|
|
3
2
|
import type { RpcOptions } from '@protobuf-ts/runtime-rpc';
|
|
4
3
|
import type { Dispatcher } from 'undici';
|
|
5
4
|
import type { ResourceType } from './types';
|
|
5
|
+
import type { GrpcClientProviderFactory } from './grpc';
|
|
6
6
|
|
|
7
7
|
/** Drivers must implement this interface */
|
|
8
8
|
export interface PlDriver {
|
|
@@ -15,7 +15,7 @@ export interface PlDriverDefinition<Drv extends PlDriver> {
|
|
|
15
15
|
readonly name: string;
|
|
16
16
|
|
|
17
17
|
/** Initialization routine, will be executed only once for each driver in a specific client */
|
|
18
|
-
init(pl: PlClient,
|
|
18
|
+
init(pl: PlClient, grpcClientProviderFactory: GrpcClientProviderFactory, httpDispatcher: Dispatcher): Drv;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// addRTypeToMetadata adds a metadata with resource type
|
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/grpc.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GrpcTransport } from '@protobuf-ts/grpc-transport';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A provider for a grpc client.
|
|
5
|
+
* The client is created on demand, and is reset when the transport is reset.
|
|
6
|
+
* This is useful for cases where the client is used in a loop, and the transport is reset after each iteration.
|
|
7
|
+
*/
|
|
8
|
+
export interface GrpcClientProvider<Client> {
|
|
9
|
+
get(): Client;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A factory for grpc client providers.
|
|
14
|
+
*/
|
|
15
|
+
export interface GrpcClientProviderFactory {
|
|
16
|
+
createGrpcClientProvider<Client>(clientConstructor: (transport: GrpcTransport) => Client): GrpcClientProvider<Client>;
|
|
17
|
+
}
|
package/src/core/ll_client.ts
CHANGED
|
@@ -21,14 +21,31 @@ import { parsePlJwt } from '../util/pl';
|
|
|
21
21
|
import type { Dispatcher } from 'undici';
|
|
22
22
|
import { inferAuthRefreshTime } from './auth';
|
|
23
23
|
import { defaultHttpDispatcher } from '@milaboratories/pl-http';
|
|
24
|
+
import type { GrpcClientProvider, GrpcClientProviderFactory } from './grpc';
|
|
24
25
|
|
|
25
26
|
export interface PlCallOps {
|
|
26
27
|
timeout?: number;
|
|
27
28
|
abortSignal?: AbortSignal;
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
class GrpcClientProviderImpl<Client> implements GrpcClientProvider<Client> {
|
|
32
|
+
private client: Client | undefined = undefined;
|
|
33
|
+
|
|
34
|
+
constructor(private readonly grpcTransport: () => GrpcTransport, private readonly clientConstructor: (transport: GrpcTransport) => Client) {}
|
|
35
|
+
|
|
36
|
+
public reset(): void {
|
|
37
|
+
this.client = undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public get(): Client {
|
|
41
|
+
if (this.client === undefined)
|
|
42
|
+
this.client = this.clientConstructor(this.grpcTransport());
|
|
43
|
+
return this.client;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
30
47
|
/** Abstract out low level networking and authorization details */
|
|
31
|
-
export class LLPlClient {
|
|
48
|
+
export class LLPlClient implements GrpcClientProviderFactory {
|
|
32
49
|
public readonly conf: PlClientConfig;
|
|
33
50
|
|
|
34
51
|
/** Initial authorization information */
|
|
@@ -47,7 +64,9 @@ export class LLPlClient {
|
|
|
47
64
|
|
|
48
65
|
private readonly grpcInterceptors: Interceptor[];
|
|
49
66
|
private _grpcTransport!: GrpcTransport;
|
|
50
|
-
private
|
|
67
|
+
private readonly providers: WeakRef<GrpcClientProviderImpl<any>>[] = [];
|
|
68
|
+
|
|
69
|
+
public readonly grpcPl: GrpcClientProvider<PlatformClient>;
|
|
51
70
|
|
|
52
71
|
public readonly httpDispatcher: Dispatcher;
|
|
53
72
|
|
|
@@ -89,6 +108,8 @@ export class LLPlClient {
|
|
|
89
108
|
this.statusListener = statusListener;
|
|
90
109
|
statusListener(this._status);
|
|
91
110
|
}
|
|
111
|
+
|
|
112
|
+
this.grpcPl = this.createGrpcClientProvider((transport) => new PlatformClient(transport));
|
|
92
113
|
}
|
|
93
114
|
|
|
94
115
|
/**
|
|
@@ -125,17 +146,52 @@ export class LLPlClient {
|
|
|
125
146
|
const oldTransport = this._grpcTransport;
|
|
126
147
|
|
|
127
148
|
this._grpcTransport = new GrpcTransport(grpcOptions);
|
|
128
|
-
|
|
149
|
+
|
|
150
|
+
// Reset all providers to let them reinitialize their clients
|
|
151
|
+
for (let i = 0; i < this.providers.length; i++) {
|
|
152
|
+
const provider = this.providers[i].deref();
|
|
153
|
+
if (provider === undefined) {
|
|
154
|
+
// at the same time we need to remove providers that are no longer valid
|
|
155
|
+
this.providers.splice(i, 1);
|
|
156
|
+
i--;
|
|
157
|
+
} else {
|
|
158
|
+
provider.reset();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
129
161
|
|
|
130
162
|
if (oldTransport !== undefined) oldTransport.close();
|
|
131
163
|
}
|
|
132
164
|
|
|
133
|
-
|
|
134
|
-
|
|
165
|
+
private providerCleanupCounter = 0;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Creates a provider for a grpc client. Returned provider will create fresh client whenever the underlying transport is reset.
|
|
169
|
+
*
|
|
170
|
+
* @param clientConstructor - a factory function that creates a grpc client
|
|
171
|
+
*/
|
|
172
|
+
public createGrpcClientProvider<Client>(clientConstructor: (transport: GrpcTransport) => Client): GrpcClientProvider<Client> {
|
|
173
|
+
// We need to cleanup providers periodically to avoid memory leaks.
|
|
174
|
+
// This is a simple heuristic to avoid memory leaks.
|
|
175
|
+
// We could use a more sophisticated algorithm, but this is good enough for now.
|
|
176
|
+
this.providerCleanupCounter++;
|
|
177
|
+
if (this.providerCleanupCounter >= 16) {
|
|
178
|
+
for (let i = 0; i < this.providers.length; i++) {
|
|
179
|
+
const provider = this.providers[i].deref();
|
|
180
|
+
if (provider === undefined) {
|
|
181
|
+
this.providers.splice(i, 1);
|
|
182
|
+
i--;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
this.providerCleanupCounter = 0;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const provider = new GrpcClientProviderImpl<Client>(() => this._grpcTransport, clientConstructor);
|
|
189
|
+
this.providers.push(new WeakRef(provider));
|
|
190
|
+
return provider;
|
|
135
191
|
}
|
|
136
192
|
|
|
137
|
-
public get
|
|
138
|
-
return this.
|
|
193
|
+
public get grpcTransport(): GrpcTransport {
|
|
194
|
+
return this._grpcTransport;
|
|
139
195
|
}
|
|
140
196
|
|
|
141
197
|
/** Returns true if client is authenticated. Even with anonymous auth information
|
|
@@ -182,7 +238,7 @@ export class LLPlClient {
|
|
|
182
238
|
this.authRefreshInProgress = true;
|
|
183
239
|
void (async () => {
|
|
184
240
|
try {
|
|
185
|
-
const response = await this.grpcPl.getJWTToken({
|
|
241
|
+
const response = await this.grpcPl.get().getJWTToken({
|
|
186
242
|
expiration: {
|
|
187
243
|
seconds: BigInt(this.conf.authTTLSeconds),
|
|
188
244
|
nanos: 0,
|
|
@@ -244,7 +300,7 @@ export class LLPlClient {
|
|
|
244
300
|
return new LLPlTransaction((abortSignal) => {
|
|
245
301
|
let totalAbortSignal = abortSignal;
|
|
246
302
|
if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);
|
|
247
|
-
return this.grpcPl.tx({
|
|
303
|
+
return this.grpcPl.get().tx({
|
|
248
304
|
abort: totalAbortSignal,
|
|
249
305
|
timeout:
|
|
250
306
|
ops.timeout
|
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
|
|
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,
|
package/src/core/transaction.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
393
|
-
this.
|
|
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.
|
|
410
|
-
this.
|
|
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.
|
|
431
|
-
this.
|
|
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.
|
|
525
|
-
this.
|
|
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.
|
|
529
|
-
this.
|
|
530
|
-
this.
|
|
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.
|
|
545
|
-
this.
|
|
546
|
-
this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
736
|
-
this.
|
|
737
|
-
for (const kv of result) this.
|
|
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.
|
|
761
|
-
this.
|
|
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.
|
|
792
|
-
this.
|
|
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.
|
|
819
|
-
this.
|
|
836
|
+
this._stat.kvGetRequests++;
|
|
837
|
+
this._stat.kvGetBytes += result?.length ?? 0;
|
|
820
838
|
|
|
821
839
|
return result;
|
|
822
840
|
}
|
|
@@ -16,11 +16,11 @@ export class UnauthenticatedPlClient {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
public async ping(): Promise<MaintenanceAPI_Ping_Response> {
|
|
19
|
-
return (await this.ll.grpcPl.ping({})).response;
|
|
19
|
+
return (await this.ll.grpcPl.get().ping({})).response;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
public async authMethods(): Promise<AuthAPI_ListMethods_Response> {
|
|
23
|
-
return (await this.ll.grpcPl.authMethods({})).response;
|
|
23
|
+
return (await this.ll.grpcPl.get().authMethods({})).response;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
public async requireAuth(): Promise<boolean> {
|
|
@@ -29,7 +29,7 @@ export class UnauthenticatedPlClient {
|
|
|
29
29
|
|
|
30
30
|
public async login(user: string, password: string): Promise<AuthInformation> {
|
|
31
31
|
try {
|
|
32
|
-
const response = await this.ll.grpcPl.getJWTToken(
|
|
32
|
+
const response = await this.ll.grpcPl.get().getJWTToken(
|
|
33
33
|
{ expiration: { seconds: BigInt(this.ll.conf.authTTLSeconds), nanos: 0 } },
|
|
34
34
|
{
|
|
35
35
|
meta: {
|
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');
|
package/src/index.ts
CHANGED