@milaboratories/pl-client 2.4.10

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 (64) hide show
  1. package/README.md +52 -0
  2. package/dist/index.cjs +14527 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.js +14426 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +49 -0
  7. package/src/core/auth.ts +27 -0
  8. package/src/core/client.test.ts +47 -0
  9. package/src/core/client.ts +302 -0
  10. package/src/core/config.test.ts +19 -0
  11. package/src/core/config.ts +197 -0
  12. package/src/core/default_client.ts +161 -0
  13. package/src/core/driver.ts +30 -0
  14. package/src/core/error.test.ts +14 -0
  15. package/src/core/errors.ts +84 -0
  16. package/src/core/http.ts +178 -0
  17. package/src/core/ll_client.test.ts +111 -0
  18. package/src/core/ll_client.ts +228 -0
  19. package/src/core/ll_transaction.test.ts +152 -0
  20. package/src/core/ll_transaction.ts +333 -0
  21. package/src/core/transaction.test.ts +173 -0
  22. package/src/core/transaction.ts +730 -0
  23. package/src/core/type_conversion.ts +121 -0
  24. package/src/core/types.test.ts +22 -0
  25. package/src/core/types.ts +223 -0
  26. package/src/core/unauth_client.test.ts +21 -0
  27. package/src/core/unauth_client.ts +48 -0
  28. package/src/helpers/pl.ts +141 -0
  29. package/src/helpers/poll.ts +178 -0
  30. package/src/helpers/rich_resource_types.test.ts +22 -0
  31. package/src/helpers/rich_resource_types.ts +84 -0
  32. package/src/helpers/smart_accessors.ts +146 -0
  33. package/src/helpers/state_helpers.ts +5 -0
  34. package/src/helpers/tx_helpers.ts +24 -0
  35. package/src/index.ts +14 -0
  36. package/src/proto/github.com/googleapis/googleapis/google/rpc/status.ts +125 -0
  37. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.ts +45 -0
  38. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.ts +271 -0
  39. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.ts +51 -0
  40. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.ts +380 -0
  41. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.ts +59 -0
  42. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.ts +450 -0
  43. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.ts +148 -0
  44. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.ts +706 -0
  45. package/src/proto/github.com/milaboratory/pl/plapi/plapiproto/api.client.ts +406 -0
  46. package/src/proto/github.com/milaboratory/pl/plapi/plapiproto/api.ts +12636 -0
  47. package/src/proto/github.com/milaboratory/pl/plapi/plapiproto/api_types.ts +1384 -0
  48. package/src/proto/github.com/milaboratory/pl/plapi/plapiproto/base_types.ts +181 -0
  49. package/src/proto/github.com/milaboratory/pl/plapi/plapiproto/import.ts +251 -0
  50. package/src/proto/github.com/milaboratory/pl/plapi/plapiproto/resource_types.ts +693 -0
  51. package/src/proto/google/api/http.ts +687 -0
  52. package/src/proto/google/protobuf/any.ts +326 -0
  53. package/src/proto/google/protobuf/descriptor.ts +4502 -0
  54. package/src/proto/google/protobuf/duration.ts +230 -0
  55. package/src/proto/google/protobuf/empty.ts +81 -0
  56. package/src/proto/google/protobuf/struct.ts +482 -0
  57. package/src/proto/google/protobuf/timestamp.ts +287 -0
  58. package/src/proto/google/protobuf/wrappers.ts +751 -0
  59. package/src/test/test_config.test.ts +6 -0
  60. package/src/test/test_config.ts +166 -0
  61. package/src/util/branding.ts +4 -0
  62. package/src/util/pl.ts +11 -0
  63. package/src/util/util.test.ts +10 -0
  64. package/src/util/util.ts +9 -0
@@ -0,0 +1,6 @@
1
+ import { getTestClientConf } from './test_config';
2
+
3
+ test('test that test config have no alternative root set', async () => {
4
+ const { conf } = await getTestClientConf();
5
+ expect(conf.alternativeRoot).toBeUndefined();
6
+ });
@@ -0,0 +1,166 @@
1
+ import * as fs from 'node:fs';
2
+ import { LLPlClient } from '../core/ll_client';
3
+ import { AuthInformation, AuthOps, plAddressToConfig, PlClientConfig } from '../core/config';
4
+ import { UnauthenticatedPlClient } from '../core/unauth_client';
5
+ import { PlClient } from '../core/client';
6
+ import { randomUUID } from 'crypto';
7
+ import { NullResourceId, OptionalResourceId, ResourceId, resourceIdToString } from '../core/types';
8
+ import { inferAuthRefreshTime } from '../core/auth';
9
+ import * as path from 'node:path';
10
+
11
+ export interface TestConfig {
12
+ address: string;
13
+ test_proxy?: string;
14
+ test_user?: string;
15
+ test_password?: string;
16
+ }
17
+
18
+ const CONFIG_FILE = 'test_config.json';
19
+ // const AUTH_DATA_FILE = '.test_auth.json';
20
+
21
+ let authDataFilePath: string | undefined;
22
+
23
+ function getFullAuthDataFilePath() {
24
+ if (authDataFilePath === undefined) authDataFilePath = path.resolve('.test_auth.json');
25
+ return authDataFilePath;
26
+ }
27
+
28
+ export function getTestConfig(): TestConfig {
29
+ let conf: Partial<TestConfig> = {};
30
+ if (fs.existsSync(CONFIG_FILE))
31
+ conf = JSON.parse(fs.readFileSync(CONFIG_FILE, { encoding: 'utf-8' }));
32
+
33
+ if (process.env.PL_ADDRESS !== undefined) conf.address = process.env.PL_ADDRESS;
34
+
35
+ if (process.env.PL_TEST_USER !== undefined) conf.test_user = process.env.PL_TEST_USER;
36
+
37
+ if (process.env.PL_TEST_PASSWORD !== undefined) conf.test_password = process.env.PL_TEST_PASSWORD;
38
+
39
+ if (process.env.PL_TEST_PROXY !== undefined) conf.test_proxy = process.env.PL_TEST_PROXY;
40
+
41
+ if (conf.address === undefined)
42
+ throw new Error(
43
+ `can't resolve platform address (checked ${CONFIG_FILE} file and PL_ADDRESS environment var)`
44
+ );
45
+
46
+ return conf as TestConfig;
47
+ }
48
+
49
+ interface AuthCache {
50
+ /** To check if config changed */
51
+ conf: TestConfig;
52
+ expiration: number;
53
+ authInformation: AuthInformation;
54
+ }
55
+
56
+ function saveAuthInfoCallback(tConf: TestConfig): (authInformation: AuthInformation) => void {
57
+ return (authInformation) => {
58
+ const dst = getFullAuthDataFilePath();
59
+ const tmpDst = getFullAuthDataFilePath() + randomUUID();
60
+ fs.writeFileSync(
61
+ tmpDst,
62
+ Buffer.from(
63
+ JSON.stringify({
64
+ conf: tConf,
65
+ authInformation,
66
+ expiration: inferAuthRefreshTime(authInformation, 24 * 60 * 60)
67
+ } as AuthCache)
68
+ ),
69
+ 'utf8'
70
+ );
71
+ fs.renameSync(tmpDst, dst);
72
+ };
73
+ }
74
+
75
+ const cleanAuthInfoCallback = () => {
76
+ console.warn(`Removing: ${getFullAuthDataFilePath()}`);
77
+ fs.rmSync(getFullAuthDataFilePath());
78
+ };
79
+
80
+ export async function getTestClientConf(): Promise<{ conf: PlClientConfig; auth: AuthOps }> {
81
+ const tConf = getTestConfig();
82
+
83
+ let authInformation: AuthInformation | undefined = undefined;
84
+
85
+ // try recover from cache
86
+ if (fs.existsSync(getFullAuthDataFilePath())) {
87
+ try {
88
+ const cache: AuthCache = JSON.parse(
89
+ fs.readFileSync(getFullAuthDataFilePath(), { encoding: 'utf-8' })
90
+ );
91
+ if (
92
+ cache.conf.address === tConf.address &&
93
+ cache.conf.test_user === tConf.test_user &&
94
+ cache.conf.test_password === tConf.test_password &&
95
+ cache.expiration > Date.now()
96
+ )
97
+ authInformation = cache.authInformation;
98
+ } catch (e: any) {
99
+ // removing cache file on any error
100
+ fs.rmSync(getFullAuthDataFilePath());
101
+ }
102
+ }
103
+
104
+ const plConf = plAddressToConfig(tConf.address);
105
+
106
+ const uClient = new UnauthenticatedPlClient(plConf);
107
+
108
+ const requireAuth = await uClient.requireAuth();
109
+
110
+ if (!requireAuth && (tConf.test_user !== undefined || tConf.test_password !== undefined))
111
+ throw new Error(
112
+ `Server require no auth, but test user name or test password are provided via (${CONFIG_FILE}) or env variables: PL_TEST_USER and PL_TEST_PASSWORD`
113
+ );
114
+
115
+ if (requireAuth && (tConf.test_user === undefined || tConf.test_password === undefined))
116
+ throw new Error(
117
+ `No auth information found in config (${CONFIG_FILE}) or env variables: PL_TEST_USER and PL_TEST_PASSWORD`
118
+ );
119
+
120
+ if (authInformation === undefined) {
121
+ if (requireAuth) authInformation = await uClient.login(tConf.test_user!, tConf.test_password!);
122
+ // No authorization is required
123
+ else authInformation = {};
124
+
125
+ // saving cache
126
+ saveAuthInfoCallback(tConf)(authInformation);
127
+ }
128
+
129
+ return {
130
+ conf: plConf,
131
+ auth: {
132
+ authInformation,
133
+ onUpdate: saveAuthInfoCallback(tConf),
134
+ onAuthError: cleanAuthInfoCallback,
135
+ onUpdateError: cleanAuthInfoCallback
136
+ }
137
+ };
138
+ }
139
+
140
+ export async function getTestLLClient(confOverrides: Partial<PlClientConfig> = {}) {
141
+ const { conf, auth } = await getTestClientConf();
142
+ return new LLPlClient({ ...conf, ...confOverrides }, { auth });
143
+ }
144
+
145
+ export async function getTestClient(alternativeRoot?: string) {
146
+ const { conf, auth } = await getTestClientConf();
147
+ if (alternativeRoot !== undefined && conf.alternativeRoot !== undefined)
148
+ throw new Error('test pl address configured with alternative root');
149
+ return await PlClient.init({ ...conf, alternativeRoot }, auth);
150
+ }
151
+
152
+ export async function withTempRoot<T>(body: (pl: PlClient) => Promise<T>): Promise<T> {
153
+ const altRoot = `test_${Date.now()}_${randomUUID()}`;
154
+ let altRootId: OptionalResourceId = NullResourceId;
155
+ try {
156
+ const client = await getTestClient(altRoot);
157
+ altRootId = client.clientRoot;
158
+ const value = await body(client);
159
+ const rawClient = await getTestClient();
160
+ await rawClient.deleteAlternativeRoot(altRoot);
161
+ return value;
162
+ } catch (err: any) {
163
+ console.log(`ALTERNATIVE ROOT: ${altRoot} (${resourceIdToString(altRootId)})`);
164
+ throw new Error(err.message, { cause: err });
165
+ }
166
+ }
@@ -0,0 +1,4 @@
1
+ declare const __brand: unique symbol;
2
+ type Brand<B> = { [__brand]: B };
3
+
4
+ export type Branded<T, B> = T & Brand<B>;
package/src/util/pl.ts ADDED
@@ -0,0 +1,11 @@
1
+ export type PlJWTPayload = {
2
+ user: {
3
+ login: string;
4
+ };
5
+ exp: number;
6
+ iat: number;
7
+ };
8
+
9
+ export function parsePlJwt(token: string): PlJWTPayload {
10
+ return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
11
+ }
@@ -0,0 +1,10 @@
1
+ import { toBytes } from './util';
2
+
3
+ test('test toBytes 1', () => {
4
+ const arr = new Uint8Array([1, 2, 3]);
5
+ expect(toBytes(arr)).toEqual(arr);
6
+ });
7
+
8
+ test('test toBytes 2', () => {
9
+ expect(toBytes('\x01\x02\x03')).toEqual(Buffer.from(new Uint8Array([1, 2, 3])));
10
+ });
@@ -0,0 +1,9 @@
1
+ function isArrayBufferOrView(value: unknown): value is ArrayBufferLike {
2
+ return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
3
+ }
4
+
5
+ export function toBytes(value: string | Uint8Array): Uint8Array {
6
+ if (typeof value === 'string') return Buffer.from(value);
7
+ else if (isArrayBufferOrView(value)) return value;
8
+ else throw new Error(`Unexpected type: ${value}`);
9
+ }