@milaboratories/pl-middle-layer 1.37.4 → 1.37.6

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 (35) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +40 -14
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +1747 -1468
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/mutator/context_export.d.ts +2 -2
  8. package/dist/mutator/context_export.d.ts.map +1 -1
  9. package/dist/mutator/template/render_template.d.ts +2 -2
  10. package/dist/mutator/template/render_template.d.ts.map +1 -1
  11. package/dist/network_check/network_check.d.ts +40 -0
  12. package/dist/network_check/network_check.d.ts.map +1 -0
  13. package/dist/network_check/network_check.test.d.ts.map +1 -0
  14. package/dist/network_check/pings.d.ts +32 -0
  15. package/dist/network_check/pings.d.ts.map +1 -0
  16. package/dist/network_check/template.d.ts +33 -0
  17. package/dist/network_check/template.d.ts.map +1 -0
  18. package/dist/network_check/template.test.d.ts +2 -0
  19. package/dist/network_check/template.test.d.ts.map +1 -0
  20. package/dist/network_check/test_utils.d.ts +6 -0
  21. package/dist/network_check/test_utils.d.ts.map +1 -0
  22. package/package.json +10 -10
  23. package/src/index.ts +1 -1
  24. package/src/mutator/template/render_template.ts +2 -2
  25. package/src/{network_check.test.ts → network_check/network_check.test.ts} +3 -3
  26. package/src/network_check/network_check.ts +369 -0
  27. package/src/network_check/pings.ts +154 -0
  28. package/src/network_check/template.test.ts +83 -0
  29. package/src/network_check/template.ts +330 -0
  30. package/src/network_check/test_utils.ts +9 -0
  31. package/dist/network_check.d.ts +0 -29
  32. package/dist/network_check.d.ts.map +0 -1
  33. package/dist/network_check.test.d.ts.map +0 -1
  34. package/src/network_check.ts +0 -329
  35. /package/dist/{network_check.test.d.ts → network_check/network_check.test.d.ts} +0 -0
@@ -0,0 +1,154 @@
1
+ import type { ValueOrError } from '@milaboratories/ts-helpers';
2
+ import { setTimeout } from 'node:timers/promises';
3
+ import { request } from 'undici';
4
+ import type { Dispatcher } from 'undici';
5
+ import type { CheckNetworkOpts } from './network_check';
6
+ import { UnauthenticatedPlClient, type PlClientConfig } from '@milaboratories/pl-client';
7
+
8
+ /** A report about one concrete ping to the service. */
9
+ export interface NetworkReport<T> {
10
+ elapsedMs: number;
11
+ response: ValueOrError<T>;
12
+ }
13
+
14
+ export type HttpNetworkReport = NetworkReport<{
15
+ statusCode: number;
16
+ beginningOfBody: string;
17
+ }>;
18
+
19
+ export async function backendPings(ops: CheckNetworkOpts, plConfig: PlClientConfig): Promise<NetworkReport<string>[]> {
20
+ return await recordPings(ops.pingCheckDurationMs, ops.maxPingsPerSecond, async () => {
21
+ const uaClient = new UnauthenticatedPlClient(plConfig);
22
+ const response = await uaClient.ping();
23
+ return JSON.stringify(response).slice(0, ops.bodyLimit) + '...';
24
+ });
25
+ }
26
+
27
+ export async function blockRegistryOverviewPings(ops: CheckNetworkOpts, httpClient: Dispatcher): Promise<HttpNetworkReport[]> {
28
+ return await recordPings(
29
+ ops.blockRegistryDurationMs,
30
+ ops.maxRegistryChecksPerSecond,
31
+ async () =>
32
+ await requestUrl(new URL(ops.blockOverviewPath, ops.blockRegistryUrl), ops, httpClient),
33
+ );
34
+ }
35
+
36
+ export async function blockGARegistryOverviewPings(ops: CheckNetworkOpts, httpClient: Dispatcher): Promise<HttpNetworkReport[]> {
37
+ return await recordPings(
38
+ ops.blockRegistryDurationMs,
39
+ ops.maxRegistryChecksPerSecond,
40
+ async () => await requestUrl(new URL(ops.blockOverviewPath, ops.blockGARegistryUrl), ops, httpClient),
41
+ );
42
+ }
43
+
44
+ export async function blockRegistryUiPings(ops: CheckNetworkOpts, httpClient: Dispatcher): Promise<HttpNetworkReport[]> {
45
+ return await recordPings(
46
+ ops.blockRegistryDurationMs,
47
+ ops.maxRegistryChecksPerSecond,
48
+ async () => await requestUrl(new URL(ops.blockUiPath, ops.blockRegistryUrl), ops, httpClient),
49
+ );
50
+ }
51
+
52
+ export async function blockGARegistryUiPings(ops: CheckNetworkOpts, httpClient: Dispatcher): Promise<HttpNetworkReport[]> {
53
+ return await recordPings(
54
+ ops.blockRegistryDurationMs,
55
+ ops.maxRegistryChecksPerSecond,
56
+ async () => await requestUrl(new URL(ops.blockUiPath, ops.blockGARegistryUrl), ops, httpClient),
57
+ );
58
+ }
59
+
60
+ export async function autoUpdateCdnPings(ops: CheckNetworkOpts, httpClient: Dispatcher): Promise<HttpNetworkReport[]> {
61
+ return await recordPings(
62
+ ops.autoUpdateCdnDurationMs,
63
+ ops.maxAutoUpdateCdnChecksPerSecond,
64
+ async () => await requestUrl(ops.autoUpdateCdnUrl, ops, httpClient),
65
+ );
66
+ }
67
+
68
+ /** Executes a body several times per second up to the given duration,
69
+ * and returns results and elapsed time for every result. */
70
+ export async function recordPings<T>(
71
+ pingCheckDurationMs: number,
72
+ maxPingsPerSecond: number,
73
+ body: () => Promise<T>,
74
+ ): Promise<NetworkReport<T>[]> {
75
+ const startPings = Date.now();
76
+ const reports: NetworkReport<T>[] = [];
77
+
78
+ while (elapsed(startPings) < pingCheckDurationMs) {
79
+ const startPing = Date.now();
80
+ let response: ValueOrError<T>;
81
+ try {
82
+ response = { ok: true, value: await body() };
83
+ } catch (e) {
84
+ response = { ok: false, error: e };
85
+ }
86
+ const elapsedPing = elapsed(startPing);
87
+
88
+ reports.push({
89
+ elapsedMs: elapsedPing,
90
+ response,
91
+ });
92
+
93
+ const sleepBetweenPings = 1000 / maxPingsPerSecond - elapsedPing;
94
+
95
+ if (sleepBetweenPings > 0) {
96
+ await setTimeout(sleepBetweenPings);
97
+ }
98
+ }
99
+
100
+ return reports;
101
+ }
102
+
103
+ export async function requestUrl(url: string | URL, ops: CheckNetworkOpts, httpClient: Dispatcher) {
104
+ const { body: rawBody, statusCode } = await request(url, {
105
+ dispatcher: httpClient,
106
+ headersTimeout: ops.httpTimeoutMs,
107
+ bodyTimeout: ops.httpTimeoutMs,
108
+ });
109
+ const body = await rawBody.text();
110
+
111
+ return {
112
+ statusCode: statusCode,
113
+ beginningOfBody: body.slice(0, ops.bodyLimit) + '...',
114
+ };
115
+ }
116
+
117
+ export function elapsed(startMs: number): number {
118
+ return Date.now() - startMs;
119
+ }
120
+
121
+ export function reportToString<T>(report: NetworkReport<T>[]): {
122
+ ok: boolean;
123
+ details: string;
124
+ } {
125
+ const successes = report.filter((r) => r.response.ok);
126
+ const errorsLen = report.length - successes.length;
127
+ const { mean: mean, median: median } = elapsedStat(report);
128
+
129
+ const details = `
130
+ total: ${report.length};
131
+ successes: ${successes.length};
132
+ errors: ${errorsLen};
133
+ mean in ms: ${mean};
134
+ median in ms: ${median};
135
+ `;
136
+
137
+ return {
138
+ ok: errorsLen === 0,
139
+ details,
140
+ };
141
+ }
142
+
143
+ function elapsedStat(reports: { elapsedMs: number }[]) {
144
+ const checks = reports.map((p) => p.elapsedMs).sort();
145
+ const mean = checks.reduce((sum, p) => sum + p) / checks.length;
146
+
147
+ let median = undefined;
148
+ if (checks.length > 0) {
149
+ const mid = Math.floor(checks.length / 2);
150
+ median = checks.length % 2 ? checks[mid] : (checks[mid - 1] + checks[mid]) / 2;
151
+ }
152
+
153
+ return { mean, median };
154
+ }
@@ -0,0 +1,83 @@
1
+ import { createBigTempFile, runDownloadFile, runPythonSoftware, runSoftware, runUploadFile, runUploadTemplate } from './template';
2
+ import { initNetworkCheck } from './network_check';
3
+ import { testCredentials } from './test_utils';
4
+ import { test, expect } from 'vitest';
5
+ import path from 'path';
6
+
7
+ test('check runUploadTemplate', async () => {
8
+ const { plEndpoint, plUser, plPassword } = testCredentials();
9
+ const { logger, client, terminate } = await initNetworkCheck(plEndpoint, plUser, plPassword);
10
+
11
+ const greeting = await runUploadTemplate(logger, client, 'Jason');
12
+
13
+ expect(greeting).toBe('Hello, Jason');
14
+
15
+ await terminate();
16
+ });
17
+
18
+ test('check runUploadFile', async () => {
19
+ const { plEndpoint, plUser, plPassword } = testCredentials();
20
+ const {
21
+ logger,
22
+ lsDriver,
23
+ uploadBlobClient,
24
+ client,
25
+ terminate,
26
+ } = await initNetworkCheck(plEndpoint, plUser, plPassword);
27
+
28
+ const { filePath } = await createBigTempFile();
29
+
30
+ const blob = await runUploadFile(
31
+ logger,
32
+ lsDriver,
33
+ uploadBlobClient,
34
+ client,
35
+ filePath,
36
+ );
37
+
38
+ expect(blob.type.name).toBe('Blob');
39
+
40
+ await terminate();
41
+ });
42
+
43
+ test('check runDownloadFile', async () => {
44
+ const { plEndpoint, plUser, plPassword } = testCredentials();
45
+ const {
46
+ logger,
47
+ lsDriver,
48
+ uploadBlobClient,
49
+ downloadClient,
50
+ client,
51
+ terminate,
52
+ } = await initNetworkCheck(plEndpoint, plUser, plPassword);
53
+
54
+ const filePath = path.join(__dirname, '..', '..', 'test_assets', 'answer.txt');
55
+
56
+ const content = await runDownloadFile(logger, client, lsDriver, uploadBlobClient, downloadClient, filePath);
57
+
58
+ expect(content).toBe('42');
59
+
60
+ await terminate();
61
+ });
62
+
63
+ test('check runSoftware', async () => {
64
+ const { plEndpoint, plUser, plPassword } = testCredentials();
65
+ const { client, terminate } = await initNetworkCheck(plEndpoint, plUser, plPassword);
66
+
67
+ const greeting = await runSoftware(client);
68
+
69
+ expect(greeting).toBe('Hello from go binary\n');
70
+
71
+ await terminate();
72
+ });
73
+
74
+ test('check runPythonSoftware', async () => {
75
+ const { plEndpoint, plUser, plPassword } = testCredentials();
76
+ const { client, terminate } = await initNetworkCheck(plEndpoint, plUser, plPassword);
77
+
78
+ const greeting = await runPythonSoftware(client, 'John');
79
+
80
+ expect(greeting).toBe('Hello, John!\n');
81
+
82
+ await terminate();
83
+ });
@@ -0,0 +1,330 @@
1
+ import type { FieldId, FieldRef, PlClient, ResourceData } from '@milaboratories/pl-client';
2
+ import { type PlTransaction, ContinuePolling, field, isNotNullResourceId, isNullResourceId, Pl, poll, toGlobalFieldId } from '@milaboratories/pl-client';
3
+ import { createRenderTemplate } from '../mutator/template/render_template';
4
+ import { Templates as SdkTemplates } from '@platforma-sdk/workflow-tengo';
5
+ import type { TemplateSpecAny } from '../model/template_spec';
6
+ import { loadTemplate, prepareTemplateSpec } from '../mutator/template/template_loading';
7
+ import type { ClientDownload, LsDriver } from '@milaboratories/pl-drivers';
8
+ import { ImportFileHandleUploadData, uploadBlob, type ClientUpload } from '@milaboratories/pl-drivers';
9
+ import { notEmpty, type MiLogger } from '@milaboratories/ts-helpers';
10
+ import type { ResourceInfo } from '@milaboratories/pl-tree';
11
+ import { text } from 'node:stream/consumers';
12
+ import path from 'node:path';
13
+ import fs from 'node:fs/promises';
14
+ import os from 'node:os';
15
+ import { randomBytes } from 'node:crypto';
16
+
17
+ export interface TemplateReport {
18
+ ok: boolean;
19
+ message: string;
20
+ }
21
+
22
+ /** Uploads `hello-world` template and checks the output is correct. */
23
+ export async function uploadTemplate(logger: MiLogger, pl: PlClient, name: string): Promise<TemplateReport> {
24
+ try {
25
+ const gotGreeting = await runUploadTemplate(logger, pl, name);
26
+ if (gotGreeting !== `Hello, ${name}`) {
27
+ return { ok: false, message: `Template uploading failed: expected: ${name}, got: ${gotGreeting}` };
28
+ }
29
+
30
+ return { ok: true, message: `Template uploading succeeded: ${gotGreeting}` };
31
+ } catch (e: unknown) {
32
+ return { ok: false, message: `Template uploading failed: error occurred: ${e}` };
33
+ }
34
+ }
35
+
36
+ export async function runUploadTemplate(
37
+ logger: MiLogger,
38
+ pl: PlClient,
39
+ name: string,
40
+ ): Promise<string> {
41
+ const greeting = await runTemplate(
42
+ pl,
43
+ SdkTemplates['check_network.upload_template'],
44
+ true,
45
+ (tx) => ({
46
+ name: tx.createValue(Pl.JsonObject, JSON.stringify(name)),
47
+ }),
48
+ ['greeting'],
49
+ );
50
+
51
+ try {
52
+ return JSON.parse(notEmpty((await getFieldValue(pl, greeting.greeting)).data?.toString()));
53
+ } finally {
54
+ await deleteFields(pl, Object.values(greeting));
55
+ }
56
+ }
57
+
58
+ /** Uploads a file to the backend and checks the output is a Blob resource. */
59
+ export async function uploadFile(
60
+ logger: MiLogger,
61
+ lsDriver: LsDriver,
62
+ uploadClient: ClientUpload,
63
+ pl: PlClient,
64
+ filePath: string,
65
+ ): Promise<TemplateReport> {
66
+ try {
67
+ const gotBlob = await runUploadFile(logger, lsDriver, uploadClient, pl, filePath);
68
+
69
+ if (gotBlob.type.name !== 'Blob') {
70
+ return { ok: false, message: `File uploading failed: ${gotBlob.type.name}` };
71
+ }
72
+
73
+ return { ok: true, message: `File uploading succeeded: ${gotBlob.type.name}` };
74
+ } catch (e: unknown) {
75
+ return { ok: false, message: `File uploading failed: error occurred: ${e}` };
76
+ }
77
+ }
78
+
79
+ export async function runUploadFile(
80
+ logger: MiLogger,
81
+ lsDriver: LsDriver,
82
+ uploadClient: ClientUpload,
83
+ pl: PlClient,
84
+ filePath: string,
85
+ ): Promise<ResourceInfo> {
86
+ const handle = await lsDriver.getLocalFileHandle(filePath);
87
+ const result = await runTemplate(
88
+ pl,
89
+ SdkTemplates['check_network.upload_blob'],
90
+ true,
91
+ (tx) => ({
92
+ file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)),
93
+ }),
94
+ ['progress', 'file'],
95
+ );
96
+
97
+ try {
98
+ const progress = await getFieldValue(pl, result.progress);
99
+
100
+ await uploadBlob(
101
+ logger,
102
+ uploadClient,
103
+ progress,
104
+ ImportFileHandleUploadData.parse(JSON.parse(notEmpty(progress.data?.toString()))),
105
+ () => false,
106
+ {
107
+ nPartsWithThisUploadSpeed: 10,
108
+ nPartsToIncreaseUpload: 10,
109
+ currentSpeed: 10,
110
+ maxSpeed: 10,
111
+ },
112
+ );
113
+
114
+ return await getFieldValue(pl, result.file);
115
+ } finally {
116
+ await deleteFields(pl, Object.values(result));
117
+ }
118
+ }
119
+
120
+ /** Uploads a file to the backend and then tries to download it back. */
121
+ export async function downloadFile(
122
+ logger: MiLogger,
123
+ pl: PlClient,
124
+ lsDriver: LsDriver,
125
+ uploadClient: ClientUpload,
126
+ downloadClient: ClientDownload,
127
+ filePath: string,
128
+ fileContent: string,
129
+ ): Promise<TemplateReport> {
130
+ try {
131
+ const gotFileContent = await runDownloadFile(logger, pl, lsDriver, uploadClient, downloadClient, filePath);
132
+
133
+ if (gotFileContent !== fileContent) {
134
+ return { ok: false, message: `File downloading failed: expected: ${fileContent}, got: ${gotFileContent}` };
135
+ }
136
+ return { ok: true, message: `File downloading succeeded: ${gotFileContent}` };
137
+ } catch (e: unknown) {
138
+ return { ok: false, message: `File downloading failed: error occurred: ${e}` };
139
+ }
140
+ }
141
+
142
+ export async function runDownloadFile(
143
+ logger: MiLogger,
144
+ pl: PlClient,
145
+ lsDriver: LsDriver,
146
+ uploadClient: ClientUpload,
147
+ downloadClient: ClientDownload,
148
+ filePath: string,
149
+ ) {
150
+ const handle = await lsDriver.getLocalFileHandle(filePath);
151
+
152
+ const outputs = await runTemplate(
153
+ pl,
154
+ SdkTemplates['check_network.download_blob'],
155
+ true,
156
+ (tx) => ({ file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)) }),
157
+ ['progress', 'file'],
158
+ );
159
+
160
+ try {
161
+ const progress = await getFieldValue(pl, outputs.progress);
162
+
163
+ await uploadBlob(
164
+ logger,
165
+ uploadClient,
166
+ progress,
167
+ ImportFileHandleUploadData.parse(JSON.parse(notEmpty(progress.data?.toString()))),
168
+ () => false,
169
+ {
170
+ nPartsWithThisUploadSpeed: 1,
171
+ nPartsToIncreaseUpload: 1,
172
+ currentSpeed: 1,
173
+ maxSpeed: 1,
174
+ },
175
+ );
176
+
177
+ const fileInfo = await getFieldValue(pl, outputs.file);
178
+ const { content } = await downloadClient.downloadBlob(fileInfo);
179
+
180
+ return await text(content);
181
+ } finally {
182
+ await deleteFields(pl, Object.values(outputs));
183
+ }
184
+ }
185
+
186
+ /** Runs Go's hello-world binary. */
187
+ export async function softwareCheck(pl: PlClient): Promise<TemplateReport> {
188
+ try {
189
+ const gotGreeting = await runSoftware(pl);
190
+
191
+ if (gotGreeting !== 'Hello from go binary\n') {
192
+ return { ok: false, message: `Software check failed: got: ${gotGreeting}` };
193
+ }
194
+ return { ok: true, message: `Software check succeeded: ${gotGreeting}` };
195
+ } catch (e: unknown) {
196
+ return { ok: false, message: `Software check failed: error occurred: ${e}` };
197
+ }
198
+ }
199
+
200
+ export async function runSoftware(pl: PlClient): Promise<string> {
201
+ const result = await runTemplate(
202
+ pl,
203
+ SdkTemplates['check_network.run_hello_world'],
204
+ true,
205
+ (_: PlTransaction) => ({}),
206
+ ['greeting'],
207
+ );
208
+
209
+ try {
210
+ return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());
211
+ } finally {
212
+ await deleteFields(pl, Object.values(result));
213
+ }
214
+ }
215
+
216
+ /** Runs Python hello-world. */
217
+ export async function pythonSoftware(pl: PlClient, name: string): Promise<TemplateReport> {
218
+ try {
219
+ const gotGreeting = await runPythonSoftware(pl, name);
220
+
221
+ if (gotGreeting !== `Hello, ${name}!\n`) {
222
+ return { ok: false, message: `Python software check failed: got: ${gotGreeting}` };
223
+ }
224
+ return { ok: true, message: `Python software check succeeded: ${gotGreeting}` };
225
+ } catch (e: unknown) {
226
+ return { ok: false, message: `Python software check failed: error occurred: ${e}` };
227
+ }
228
+ }
229
+
230
+ export async function runPythonSoftware(pl: PlClient, name: string): Promise<string> {
231
+ const result = await runTemplate(
232
+ pl,
233
+ SdkTemplates['check_network.run_hello_world_py'],
234
+ true,
235
+ (tx) => ({ name: tx.createValue(Pl.JsonObject, JSON.stringify(name)) }),
236
+ ['greeting'],
237
+ );
238
+
239
+ try {
240
+ return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());
241
+ } finally {
242
+ await deleteFields(pl, Object.values(result));
243
+ }
244
+ }
245
+
246
+ /** Creates a big temporary file with random content. */
247
+ export async function createBigTempFile(): Promise<{ filePath: string }> {
248
+ const filePath = path.join(os.tmpdir(), `check-network-big-temp-${Date.now()}.bin`);
249
+ const fileSize = 20 * 1024 * 1024; // 20 MiB
250
+
251
+ const fileContent = randomBytes(fileSize);
252
+
253
+ await fs.appendFile(filePath, fileContent);
254
+
255
+ return { filePath };
256
+ }
257
+
258
+ /** Creates a temporarly file we could use for uploading and downloading. */
259
+ export async function createTempFile(): Promise<{ filePath: string; fileContent: string }> {
260
+ const filePath = path.join(os.tmpdir(), `check-network-temp-${Date.now()}.txt`);
261
+
262
+ const fileContent = 'Hello, world! ' + new Date().toISOString();
263
+ await fs.writeFile(filePath, fileContent);
264
+
265
+ return { filePath, fileContent };
266
+ }
267
+
268
+ /** Creates a template and RenderTemplate resources, gets all resources from outputs.
269
+ * Throws a error if any of the outputs failed.
270
+ */
271
+ async function runTemplate(
272
+ client: PlClient,
273
+ tpl: TemplateSpecAny,
274
+ ephemeral: boolean,
275
+ inputs: (tx: PlTransaction) => Pl.PlRecord,
276
+ outputs: string[],
277
+ ): Promise<Record<string, FieldId>> {
278
+ return await client.withWriteTx('TemplateRender', async (tx) => {
279
+ const preparedTemplate = await prepareTemplateSpec(tpl);
280
+ const tplResource = loadTemplate(tx, preparedTemplate);
281
+
282
+ const outputFields: Record<string, FieldRef> = createRenderTemplate(
283
+ tx, tplResource, ephemeral, inputs(tx), outputs,
284
+ );
285
+
286
+ const outputsIds: Record<string, FieldId> = {};
287
+
288
+ for (const output of outputs) {
289
+ const fieldRef = field(client.clientRoot, output);
290
+ tx.createField(fieldRef, 'Dynamic', outputFields[output]);
291
+ outputsIds[output] = await toGlobalFieldId(fieldRef);
292
+ }
293
+
294
+ await tx.commit();
295
+
296
+ return outputsIds;
297
+ });
298
+ }
299
+
300
+ /** Gets a resource from field's value or throws a error. */
301
+ async function getFieldValue(
302
+ client: PlClient,
303
+ fieldId: FieldId,
304
+ ): Promise<ResourceData> {
305
+ // We could also do polling with pl-tree, but it seemed like an overkill,
306
+ // that's why we have a simple polling here.
307
+
308
+ return await poll(client, async (tx) => {
309
+ const field = await tx.tx.getField(fieldId);
310
+ if (isNotNullResourceId(field.error)) {
311
+ const err = await tx.tx.getResourceData(field.error, true);
312
+ throw new Error(`getFieldValue of "${fieldId.fieldName}" field failed: ${err.data}`);
313
+ }
314
+
315
+ if (isNullResourceId(field.value)) {
316
+ throw new ContinuePolling();
317
+ }
318
+
319
+ return await tx.tx.getResourceData(field.value, true);
320
+ });
321
+ }
322
+
323
+ async function deleteFields(client: PlClient, fieldIds: FieldId[]) {
324
+ await client.withWriteTx('DeleteFields', async (tx) => {
325
+ for (const fieldId of fieldIds) {
326
+ tx.resetField(fieldId);
327
+ }
328
+ await tx.commit();
329
+ });
330
+ }
@@ -0,0 +1,9 @@
1
+ export function testCredentials() {
2
+ expect(process.env.PL_ADDRESS).not.toBeUndefined();
3
+
4
+ return {
5
+ plEndpoint: process.env.PL_ADDRESS!,
6
+ plUser: process.env.PL_TEST_USER, // maybe undefined
7
+ plPassword: process.env.PL_TEST_PASSWORD, // maybe undefined
8
+ };
9
+ }
@@ -1,29 +0,0 @@
1
- /** A utility to check network problems and gather statistics.
2
- * It's useful when we cannot connect to the server of a company
3
- * because of security reasons,
4
- * but they can send us and their DevOps team this report. */
5
- export interface CheckNetworkOpts {
6
- /** Platforma Backend pings options. */
7
- pingCheckDurationMs: number;
8
- pingTimeoutMs: number;
9
- maxPingsPerSecond: number;
10
- /** An options for CDN and block registry. */
11
- httpTimeoutMs: number;
12
- /** Block registry pings options. */
13
- blockRegistryDurationMs: number;
14
- maxRegistryChecksPerSecond: number;
15
- blockRegistryUrl: string;
16
- blockGARegistryUrl: string;
17
- blockOverviewPath: string;
18
- blockUiPath: string;
19
- /** CDN for auto-update pings options. */
20
- autoUpdateCdnDurationMs: number;
21
- maxAutoUpdateCdnChecksPerSecond: number;
22
- autoUpdateCdnUrl: string;
23
- bodyLimit: number;
24
- }
25
- /** Checks connectivity to Platforma Backend, to block registry
26
- * and to auto-update CDN,
27
- * and generates a string report. */
28
- export declare function checkNetwork(plCredentials: string, optsOverrides?: Partial<CheckNetworkOpts>): Promise<string>;
29
- //# sourceMappingURL=network_check.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"network_check.d.ts","sourceRoot":"","sources":["../src/network_check.ts"],"names":[],"mappings":"AAAA;;;6DAG6D;AAqB7D,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAE1B,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IAEtB,oCAAoC;IACpC,uBAAuB,EAAE,MAAM,CAAC;IAChC,0BAA0B,EAAE,MAAM,CAAC;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IAEpB,yCAAyC;IACzC,uBAAuB,EAAE,MAAM,CAAC;IAChC,+BAA+B,EAAE,MAAM,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAwCD;;oCAEoC;AACpC,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,aAAa,GAAE,OAAO,CAAC,gBAAgB,CAAM,GAC5C,OAAO,CAAC,MAAM,CAAC,CAmGjB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"network_check.test.d.ts","sourceRoot":"","sources":["../src/network_check.test.ts"],"names":[],"mappings":""}