@hahnpro/hpc-api 2025.2.15 → 2025.3.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @hahnpro/hpc-api
2
2
 
3
+ ## 2025.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Added asset::findOneExternal and asset::updateOneExternal to reflect changes to asset API
8
+ - Updated some Mock Types to improve type-compliance between real and mock API classes
9
+ - Added documentation on how to develop an asset synchronization script from external systems
10
+
11
+ ## 2025.3.1
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies to reduce vulnerabilities
16
+
17
+ ## 2025.3.0
18
+
19
+ ### Patch Changes
20
+
21
+ - URL and method of the `asset::getEventLevelOverride` and `asset:updateEventCausesAsset` have been changed.
22
+
3
23
  ## 2025.2.15
4
24
 
5
25
  ### Major Changes
package/README.md CHANGED
@@ -135,7 +135,7 @@ This example uses the [`pyjwt` library](https://pyjwt.readthedocs.io/en/stable/)
135
135
  </details>
136
136
 
137
137
  <details>
138
- <summary markdown="span">Python</summary>
138
+ <summary markdown="span">Typescript</summary>
139
139
 
140
140
  Get user roles from JWT-Token.
141
141
 
@@ -483,24 +483,3 @@ await api.timeSeries.addValue('1234', value);
483
483
  ```
484
484
 
485
485
  </details>
486
-
487
- ## 4. FAQ
488
-
489
- ### 4.1. How to log messages from Python in a FlowFunction
490
-
491
- > this is just possible for _RPC_ style Python integration.
492
-
493
- In Typescript, you can register a listener for messages and `stderr` and pipe them to your `logger`.
494
-
495
- ```typescript
496
- const script = this.runPyRpcScript(join(__dirname, 'my-awesome-script.py'));
497
- script.addListener('stderr', (data) => this.logger.error('py: ' + data));
498
- script.on('message', (data) => this.logger.debug('py: ' + data));
499
- ```
500
-
501
- Then you can simply use print in python for logging
502
-
503
- ```python
504
- print("log the logging log")
505
- print("this is an error", file=sys.stderr)
506
- ```
@@ -0,0 +1,556 @@
1
+ # Asset Synchronization Documentation
2
+
3
+ This documentation describes the process for synchronizing assets and asset types with the Hahn PRO Cloud API, including synchronization using external keys.
4
+
5
+ The fundamental approaches are useful in any language, but the examples here are in typescript. At the end you will have a
6
+ complete script for synchronizing Assettypes and Assets, i.e. creating them if they don´t exist and updating existing ones.
7
+ There are multiple approaches shown here, select the one that fits your use-case.
8
+
9
+ ## Overview
10
+
11
+ The synchronization process follows two main steps:
12
+
13
+ 1. **Synchronize Asset Types**: Check and create asset types based on their names
14
+ 2. **Synchronize Assets**: Check and create assets based on their names or external keys using a similar process
15
+
16
+ ## Prerequisites
17
+
18
+ - Access to Hahn PRO Cloud API
19
+ - Valid authentication (JWT token)
20
+ - Permissions to create asset types and assets
21
+
22
+ ## Synchronization Methods
23
+
24
+ There are two approaches for asset synchronization:
25
+
26
+ 1. **Name-based synchronization**: Uses the asset name for duplicate detection
27
+ 2. **External key-based synchronization**: Uses the `externalKey` field for duplicate detection
28
+ 3. **Update mode**: Updates existing assets instead of skipping them
29
+
30
+ ## 1. Asset Type Synchronization
31
+
32
+ ### Process
33
+
34
+ 1. **Fetch existing asset types**: Load all current asset types
35
+ 2. **Name comparison**: For each asset type to be created, check if a type with the same name already exists
36
+ 3. **Check dependencies**: Ensure all parent types already exist
37
+ 4. **Create**: Create new asset types if they don't exist
38
+
39
+ ### TypeScript Implementation
40
+
41
+ ```typescript
42
+ async function synchronizeAssetTypes(assetTypes: AssetType[], orgId: string): Promise<void> {
43
+ // Load all existing asset types
44
+ const existingTypes = await api.assetTypes.getMany();
45
+ const existingTypeNames = new Set(existingTypes.docs.map((type) => type.name));
46
+
47
+ // Map for name-to-ID mapping
48
+ const assetTypeNameIdMap = new Map<string, string>();
49
+
50
+ // Populate map with existing types
51
+ existingTypes.docs.forEach((type) => {
52
+ assetTypeNameIdMap.set(type.name, type.id);
53
+ });
54
+
55
+ // Process asset types (considering dependencies)
56
+ while (assetTypes.length > 0) {
57
+ const type = assetTypes.shift();
58
+
59
+ // Check if type already exists
60
+ if (existingTypeNames.has(type.name)) {
61
+ console.log(`Asset type '${type.name}' already exists - skipping`);
62
+ continue;
63
+ }
64
+
65
+ // Check if all parent types have been created
66
+ if (!(type.allowedParents || [])?.every((parent) => assetTypeNameIdMap.has(parent))) {
67
+ // Not all parent types exist -> requeue
68
+ assetTypes.push(type);
69
+ continue;
70
+ }
71
+
72
+ try {
73
+ // Create new asset type
74
+ const created = await api.assetTypes.addOne({
75
+ ...type,
76
+ allowedParents: (type.allowedParents || []).map((parent) => assetTypeNameIdMap.get(parent)),
77
+ readWritePermissions: [...type.readWritePermissions, orgId],
78
+ });
79
+
80
+ assetTypeNameIdMap.set(type.name, created.id);
81
+ console.log(`Asset type '${type.name}' created successfully`);
82
+ } catch (error) {
83
+ console.error(`Error creating asset type '${type.name}':`, error);
84
+ throw error;
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ ## 2. Asset Synchronization by Name (Create Only)
91
+
92
+ ### Process
93
+
94
+ 1. **Fetch existing assets**: Load all current assets
95
+ 2. **Name comparison**: For each asset to be created, check if an asset with the same name already exists
96
+ 3. **Check parent dependencies**: Ensure parent assets already exist
97
+ 4. **Type mapping**: Map asset type based on name
98
+ 5. **Create**: Create new assets if they don't exist
99
+
100
+ ### TypeScript Implementation
101
+
102
+ ```typescript
103
+ async function synchronizeAssetsByName(assets: Asset[], orgId: string, updateExisting: boolean = false): Promise<void> {
104
+ // Load all existing assets
105
+ const existingAssets = await api.assets.getMany();
106
+ const existingAssetNames = new Map<string, string>(); // name -> id
107
+
108
+ // Map for name-to-ID mapping
109
+ const assetNameIdMap = new Map<string, string>();
110
+
111
+ // Populate map with existing assets
112
+ existingAssets.docs.forEach((asset) => {
113
+ assetNameIdMap.set(asset.name, asset.id);
114
+ existingAssetNames.set(asset.name, asset.id);
115
+ });
116
+
117
+ // Process assets (considering parent dependencies)
118
+ while (assets.length > 0) {
119
+ const asset = assets.shift();
120
+
121
+ // Check if asset already exists
122
+ if (existingAssetNames.has(asset.name)) {
123
+ if (updateExisting) {
124
+ try {
125
+ // Update existing asset
126
+ const existingId = existingAssetNames.get(asset.name);
127
+ const updated = await api.assets.updateOne(existingId, {
128
+ ...asset,
129
+ type: assetTypeNameIdMap.get(asset.type as string),
130
+ parent: assetNameIdMap.get(asset.parent),
131
+ readWritePermissions: [...asset.readWritePermissions, orgId],
132
+ });
133
+ console.log(`Updated existing asset '${asset.name}'`);
134
+ assetNameIdMap.set(asset.name, updated.id);
135
+ } catch (error) {
136
+ console.error(`Error updating asset '${asset.name}':`, error);
137
+ throw error;
138
+ }
139
+ } else {
140
+ console.log(`Asset '${asset.name}' already exists - skipping`);
141
+ }
142
+ continue;
143
+ }
144
+
145
+ // Check if parent asset exists (if defined)
146
+ if (asset.parent && !assetNameIdMap.has(asset.parent)) {
147
+ // Parent doesn't exist yet -> requeue
148
+ assets.push(asset);
149
+ continue;
150
+ }
151
+
152
+ // Check if asset type exists
153
+ if (!assetTypeNameIdMap.has(asset.type as string)) {
154
+ throw new Error(`Asset type '${asset.type}' not found`);
155
+ }
156
+
157
+ try {
158
+ // Create new asset
159
+ const created = await api.assets.addOne({
160
+ ...asset,
161
+ type: assetTypeNameIdMap.get(asset.type as string),
162
+ parent: assetNameIdMap.get(asset.parent),
163
+ readWritePermissions: [...asset.readWritePermissions, orgId],
164
+ });
165
+
166
+ assetNameIdMap.set(asset.name, created.id);
167
+ console.log(`Asset '${asset.name}' created successfully`);
168
+ } catch (error) {
169
+ console.error(`Error creating asset '${asset.name}':`, error);
170
+ throw error;
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ ## 3. Asset Synchronization by External Key
177
+
178
+ When synchronizing assets from external systems, you can use the `externalKey` field to identify assets. This is particularly useful when the external system has its own unique identifiers.
179
+
180
+ ### Process
181
+
182
+ 1. **Check for existing assets by external key**: Use the external endpoints to find existing assets
183
+ 2. **Update or create**: Update existing assets or create new ones based on external key presence
184
+ 3. **Handle dependencies**: Ensure parent assets exist before creating child assets
185
+
186
+ ### TypeScript Implementation
187
+
188
+ ```typescript
189
+ async function synchronizeAssetsByExternalKey(assets: Asset[], orgId: string): Promise<void> {
190
+ // Maps for tracking assets
191
+ const assetExternalKeyIdMap = new Map<string, string>();
192
+ const assetNameIdMap = new Map<string, string>();
193
+
194
+ // Process assets (considering parent dependencies)
195
+ while (assets.length > 0) {
196
+ const asset = assets.shift();
197
+
198
+ if (!asset.externalKey) {
199
+ throw new Error(`Asset '${asset.name}' missing externalKey for external synchronization`);
200
+ }
201
+
202
+ // Check if parent asset exists (if defined)
203
+ if (asset.parent && !assetNameIdMap.has(asset.parent) && !assetExternalKeyIdMap.has(asset.parent)) {
204
+ // Parent doesn't exist yet -> requeue
205
+ assets.push(asset);
206
+ continue;
207
+ }
208
+
209
+ // Check if asset type exists
210
+ if (!assetTypeNameIdMap.has(asset.type as string)) {
211
+ throw new Error(`Asset type '${asset.type}' not found`);
212
+ }
213
+
214
+ try {
215
+ // Try to find existing asset by external key
216
+ let existingAsset: Asset | null = null;
217
+ try {
218
+ existingAsset = await api.assets.findOneExternal(asset.externalKey);
219
+ console.log(`Found existing asset with external key '${asset.externalKey}'`);
220
+ } catch (error) {
221
+ // Asset doesn't exist yet - this is expected for new assets
222
+ console.log(`Asset with external key '${asset.externalKey}' not found - will create new`);
223
+ }
224
+
225
+ let resultAsset: Asset;
226
+
227
+ if (existingAsset) {
228
+ // Update existing asset using external key endpoint
229
+ resultAsset = await api.assets.updateOneExternal(asset.externalKey, {
230
+ ...asset,
231
+ type: assetTypeNameIdMap.get(asset.type as string),
232
+ parent: assetNameIdMap.get(asset.parent) || assetExternalKeyIdMap.get(asset.parent),
233
+ readWritePermissions: [...asset.readWritePermissions, orgId],
234
+ });
235
+ console.log(`Updated asset with external key '${asset.externalKey}'`);
236
+ } else {
237
+ // Create new asset
238
+ resultAsset = await api.assets.addOne({
239
+ ...asset,
240
+ type: assetTypeNameIdMap.get(asset.type as string),
241
+ parent: assetNameIdMap.get(asset.parent) || assetExternalKeyIdMap.get(asset.parent),
242
+ readWritePermissions: [...asset.readWritePermissions, orgId],
243
+ });
244
+ console.log(`Created new asset with external key '${asset.externalKey}'`);
245
+ }
246
+
247
+ // Update maps for dependency resolution
248
+ assetExternalKeyIdMap.set(asset.externalKey, resultAsset.id);
249
+ assetNameIdMap.set(asset.name, resultAsset.id);
250
+ } catch (error) {
251
+ console.error(`Error processing asset with external key '${asset.externalKey}':`, error);
252
+ throw error;
253
+ }
254
+ }
255
+ }
256
+ ```
257
+
258
+ ## 4. Mixed Synchronization (Name and External Key)
259
+
260
+ For scenarios where some assets have external keys and others don't, you can use a mixed approach:
261
+
262
+ ```typescript
263
+ async function synchronizeAssetsMixed(assets: Asset[], orgId: string, updateExisting: boolean = false): Promise<void> {
264
+ // Load all existing assets for name-based lookup
265
+ const existingAssets = await api.assets.getMany();
266
+ const existingAssetNames = new Map<string, string>(); // name -> id
267
+
268
+ // Maps for tracking assets
269
+ const assetExternalKeyIdMap = new Map<string, string>();
270
+ const assetNameIdMap = new Map<string, string>();
271
+
272
+ // Populate map with existing assets
273
+ existingAssets.docs.forEach((asset) => {
274
+ assetNameIdMap.set(asset.name, asset.id);
275
+ existingAssetNames.set(asset.name, asset.id);
276
+ if (asset.externalKey) {
277
+ assetExternalKeyIdMap.set(asset.externalKey, asset.id);
278
+ }
279
+ });
280
+
281
+ // Process assets (considering parent dependencies)
282
+ while (assets.length > 0) {
283
+ const asset = assets.shift();
284
+
285
+ // Determine identification method
286
+ const useExternalKey = !!asset.externalKey;
287
+ const identifier = useExternalKey ? asset.externalKey : asset.name;
288
+
289
+ // Check if parent asset exists (if defined)
290
+ if (asset.parent && !assetNameIdMap.has(asset.parent) && !assetExternalKeyIdMap.has(asset.parent)) {
291
+ // Parent doesn't exist yet -> requeue
292
+ assets.push(asset);
293
+ continue;
294
+ }
295
+
296
+ // Check if asset type exists
297
+ if (!assetTypeNameIdMap.has(asset.type as string)) {
298
+ throw new Error(`Asset type '${asset.type}' not found`);
299
+ }
300
+
301
+ try {
302
+ let resultAsset: Asset;
303
+ let assetExists = false;
304
+
305
+ if (useExternalKey) {
306
+ // Try to find existing asset by external key
307
+ try {
308
+ await api.assets.findOneExternal(asset.externalKey);
309
+ assetExists = true;
310
+ } catch (error) {
311
+ assetExists = false;
312
+ }
313
+
314
+ if (assetExists) {
315
+ // Update existing asset using external key endpoint
316
+ resultAsset = await api.assets.updateOneExternal(asset.externalKey, {
317
+ ...asset,
318
+ type: assetTypeNameIdMap.get(asset.type as string),
319
+ parent: assetNameIdMap.get(asset.parent) || assetExternalKeyIdMap.get(asset.parent),
320
+ readWritePermissions: [...asset.readWritePermissions, orgId],
321
+ });
322
+ console.log(`Updated asset with external key '${asset.externalKey}'`);
323
+ } else {
324
+ // Create new asset
325
+ resultAsset = await api.assets.addOne({
326
+ ...asset,
327
+ type: assetTypeNameIdMap.get(asset.type as string),
328
+ parent: assetNameIdMap.get(asset.parent) || assetExternalKeyIdMap.get(asset.parent),
329
+ readWritePermissions: [...asset.readWritePermissions, orgId],
330
+ });
331
+ console.log(`Created new asset with external key '${asset.externalKey}'`);
332
+ }
333
+ assetExternalKeyIdMap.set(asset.externalKey, resultAsset.id);
334
+ } else {
335
+ // Name-based approach
336
+ assetExists = existingAssetNames.has(asset.name);
337
+
338
+ if (assetExists && updateExisting) {
339
+ // Update existing asset using standard endpoint
340
+ const existingId = existingAssetNames.get(asset.name);
341
+ resultAsset = await api.assets.updateOne(existingId, {
342
+ ...asset,
343
+ type: assetTypeNameIdMap.get(asset.type as string),
344
+ parent: assetNameIdMap.get(asset.parent) || assetExternalKeyIdMap.get(asset.parent),
345
+ readWritePermissions: [...asset.readWritePermissions, orgId],
346
+ });
347
+ console.log(`Updated existing asset '${asset.name}'`);
348
+ } else if (assetExists && !updateExisting) {
349
+ console.log(`Asset '${asset.name}' already exists - skipping`);
350
+ continue;
351
+ } else {
352
+ // Create new asset using standard method
353
+ resultAsset = await api.assets.addOne({
354
+ ...asset,
355
+ type: assetTypeNameIdMap.get(asset.type as string),
356
+ parent: assetNameIdMap.get(asset.parent) || assetExternalKeyIdMap.get(asset.parent),
357
+ readWritePermissions: [...asset.readWritePermissions, orgId],
358
+ });
359
+ console.log(`Created asset '${asset.name}'`);
360
+ }
361
+ }
362
+
363
+ assetNameIdMap.set(asset.name, resultAsset.id);
364
+ } catch (error) {
365
+ console.error(`Error processing asset '${identifier}':`, error);
366
+ throw error;
367
+ }
368
+ }
369
+ }
370
+ ```
371
+
372
+ ## 5. Complete Synchronization Function
373
+
374
+ ```typescript
375
+ interface SynchronizationOptions {
376
+ useExternalKeys?: boolean;
377
+ updateExisting?: boolean;
378
+ mixedMode?: boolean;
379
+ }
380
+
381
+ async function synchronizeAssetsComplete(
382
+ assetTypes: AssetType[],
383
+ assets: Asset[],
384
+ orgId: string,
385
+ options: SynchronizationOptions = {},
386
+ ): Promise<void> {
387
+ const { useExternalKeys = false, updateExisting = false, mixedMode = false } = options;
388
+
389
+ console.log('Starting asset synchronization...');
390
+ console.log(`Options: External Keys: ${useExternalKeys}, Update Existing: ${updateExisting}, Mixed Mode: ${mixedMode}`);
391
+
392
+ try {
393
+ // Step 1: Synchronize asset types
394
+ console.log('Synchronizing asset types...');
395
+ await synchronizeAssetTypes([...assetTypes], orgId);
396
+
397
+ // Step 2: Synchronize assets
398
+ console.log('Synchronizing assets...');
399
+ if (mixedMode) {
400
+ await synchronizeAssetsMixed([...assets], orgId, updateExisting);
401
+ } else if (useExternalKeys) {
402
+ await synchronizeAssetsByExternalKey([...assets], orgId);
403
+ } else {
404
+ await synchronizeAssetsByName([...assets], orgId, updateExisting);
405
+ }
406
+
407
+ console.log('Asset synchronization completed successfully!');
408
+ } catch (error) {
409
+ console.error('Error during asset synchronization:', error);
410
+ throw error;
411
+ }
412
+ }
413
+ ```
414
+
415
+ ## 6. Usage Examples
416
+
417
+ ### Create Only (Skip Existing)
418
+
419
+ ```typescript
420
+ import { readFileSync } from 'fs';
421
+
422
+ import { API, Asset, AssetType } from '@hahnpro/hpc-api';
423
+
424
+ // Initialize API
425
+ const api = new API();
426
+
427
+ // Load data from JSON files
428
+ const assetTypes = JSON.parse(readFileSync('assetTypes.json', 'utf-8')) as AssetType[];
429
+ const assets = JSON.parse(readFileSync('assets.json', 'utf-8')) as Asset[];
430
+
431
+ // Organization ID
432
+ const orgId = 'your-organization-id';
433
+
434
+ // Execute synchronization - create only
435
+ await synchronizeAssetsComplete(assetTypes, assets, orgId, {
436
+ updateExisting: false,
437
+ });
438
+ ```
439
+
440
+ ### Update Existing Assets by Name
441
+
442
+ ```typescript
443
+ // Execute synchronization - update existing assets by name
444
+ await synchronizeAssetsComplete(assetTypes, assets, orgId, {
445
+ updateExisting: true,
446
+ });
447
+ ```
448
+
449
+ ### Using External Key-based Synchronization
450
+
451
+ ```typescript
452
+ // Execute synchronization using external keys (always updates existing)
453
+ await synchronizeAssetsComplete(assetTypes, assets, orgId, {
454
+ useExternalKeys: true,
455
+ });
456
+ ```
457
+
458
+ ### Mixed Mode with Updates
459
+
460
+ ```typescript
461
+ // Execute mixed mode synchronization with updates
462
+ await synchronizeAssetsComplete(assetTypes, assets, orgId, {
463
+ mixedMode: true,
464
+ updateExisting: true,
465
+ });
466
+ ```
467
+
468
+ ## Data Format
469
+
470
+ ### Asset Type JSON Structure
471
+
472
+ ```json
473
+ [
474
+ {
475
+ "name": "Building",
476
+ "allowedParents": [],
477
+ "readPermissions": [],
478
+ "readWritePermissions": ["some-role"],
479
+ "typeSchema": {
480
+ "type": "object",
481
+ "properties": {
482
+ "example": {
483
+ "type": "string",
484
+ "title": "example"
485
+ }
486
+ }
487
+ }
488
+ }
489
+ ]
490
+ ```
491
+
492
+ ### Asset JSON Structure (Name-based)
493
+
494
+ ```json
495
+ [
496
+ {
497
+ "name": "Main Building",
498
+ "type": "Building",
499
+ "readPermissions": [],
500
+ "readWritePermissions": ["some_role"],
501
+ "data": {
502
+ "example": "foo"
503
+ }
504
+ }
505
+ ]
506
+ ```
507
+
508
+ ### Asset JSON Structure (External Key-based)
509
+
510
+ ```json
511
+ [
512
+ {
513
+ "name": "Main Building",
514
+ "externalKey": "EXT-BUILDING-001",
515
+ "type": "Building",
516
+ "parent": "EXT-SITE-001",
517
+ "readPermissions": [],
518
+ "readWritePermissions": ["some_role"],
519
+ "data": {
520
+ "example": "foo"
521
+ }
522
+ }
523
+ ]
524
+ ```
525
+
526
+ ## Important Notes
527
+
528
+ - **Update Behavior**: When `updateExisting` is true, the entire asset object is replaced with the new data
529
+ - **External Key Updates**: External key synchronization always attempts to update existing assets first
530
+ - **Dependency Resolution**: Parent references can be either names or external keys, depending on the synchronization method
531
+ - **Error Handling**: The system handles both creation and update scenarios gracefully
532
+ - **Performance**: External key synchronization may be slower due to individual lookups for each asset
533
+ - **Mixed Mode**: Allows combination of name-based and external key-based assets in the same synchronization run
534
+
535
+ ## API Endpoints Used
536
+
537
+ - **Standard Asset Operations**:
538
+ - - Get all assets `GET /api/assets`
539
+ - - Create new asset `POST /api/assets`
540
+ - - Update existing asset by ID `PUT /api/assets/{id}`
541
+
542
+ - **External Key Operations**:
543
+ - - Get asset by external key `GET /api/assets/external/{key}`
544
+ - - Update asset by external key `PUT /api/assets/external/{key}`
545
+
546
+ ## Limitations
547
+
548
+ The example Code above is not an all-encompassing solution for synchronization. It has some limitations:
549
+
550
+ ### Partial state if errors occur
551
+
552
+ If some error where to occur while synchronizing, a partiality-synced state will be left behind.
553
+
554
+ ### Only Assettypes and Assets
555
+
556
+ Only these two Datatypes are synchronized. A Synchronization of other data can be done with a similar approach like shown here.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hahnpro/hpc-api",
3
- "version": "2025.2.15",
3
+ "version": "2025.3.2",
4
4
  "description": "Module for easy access to the HahnPRO Cloud API",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -8,9 +8,9 @@
8
8
  "url": "https://hahnpro.com"
9
9
  },
10
10
  "dependencies": {
11
- "axios": "1.10.0",
11
+ "axios": "1.11.0",
12
12
  "eventsource": "4.0.0",
13
- "form-data": "4.0.3",
13
+ "form-data": "4.0.4",
14
14
  "jose": "5.10.0",
15
15
  "jwt-decode": "4.0.0",
16
16
  "p-queue": "6.6.2",
@@ -65,6 +65,7 @@ export interface UserMessage extends BaseMessage {
65
65
  role: 'user';
66
66
  content?: string;
67
67
  hidden?: boolean;
68
+ useWebSearch?: boolean;
68
69
  }
69
70
  export type Message = AssistantMessage | SystemMessage | ToolMessage | UserMessage;
70
71
  export interface SpeechToken {
@@ -27,6 +27,7 @@ export type AssetTypeRevision = AssetType & {
27
27
  };
28
28
  export interface Asset {
29
29
  id?: string;
30
+ externalKey?: string;
30
31
  name: string;
31
32
  type: string | AssetType;
32
33
  type$name?: string;
@@ -15,6 +15,7 @@ import { Label } from '../label.interface';
15
15
  import { NotificationRuleService } from '../notification-rule.service';
16
16
  import { Notification } from '../notification.interface';
17
17
  import { Organization } from '../organization.interface';
18
+ import { ProxyService } from '../proxy.service';
18
19
  import { Secret } from '../secret.interface';
19
20
  import { AiService } from '../services';
20
21
  import { Artifact } from '../storage.interface';
@@ -71,7 +72,7 @@ export declare class MockAPI implements API {
71
72
  flowModules: FlowModuleService;
72
73
  labels: LabelMockService;
73
74
  notificationRules: NotificationRuleService;
74
- proxy: any;
75
+ proxy: ProxyService;
75
76
  secrets: SecretMockService;
76
77
  tasks: TaskMockService;
77
78
  timeSeries: TimeseriesMockService;
@@ -80,6 +81,7 @@ export declare class MockAPI implements API {
80
81
  notifications: NotificationMockService;
81
82
  organizations: OrganizationMockService;
82
83
  constructor(initData: MockAPIInitData);
84
+ getEverything(): Promise<{}>;
83
85
  }
84
86
  export type Identity<T> = {
85
87
  [P in keyof T]: T[P];
@@ -206,5 +206,31 @@ class MockAPI {
206
206
  this.organizations = new organization_mock_service_1.OrganizationMockService(organizations1);
207
207
  this.httpClient = new http_mock_service_1.HttpMockService();
208
208
  }
209
+ async getEverything() {
210
+ const results = {
211
+ assets: await this.assets.getMany(),
212
+ assetTypes: await this.assetTypes.getMany(),
213
+ contents: await this.contents.getMany(),
214
+ endpoints: await this.endpoints.getMany(),
215
+ secrets: await this.secrets.getMany(),
216
+ timeSeries: await this.timeSeries.getMany(),
217
+ tasks: await this.tasks.getMany(),
218
+ events: await this.events.getMany(),
219
+ flows: await this.flows.getMany(),
220
+ flowDeployments: await this.flowDeployments.getMany(),
221
+ flowFunctions: await this.flowFunctions.getMany(),
222
+ flowModules: await this.flowModules.getMany(),
223
+ labels: await this.labels.getMany(),
224
+ vault: await this.vault.getMany(),
225
+ notifications: await this.notifications.getMany(),
226
+ organizations: await this.organizations.getMany(),
227
+ };
228
+ return Object.keys(results).reduce((previousValue, currentValue) => {
229
+ if (results[currentValue].total > 0) {
230
+ previousValue[currentValue] = results[currentValue];
231
+ }
232
+ return previousValue;
233
+ }, {});
234
+ }
209
235
  }
210
236
  exports.MockAPI = MockAPI;
@@ -1,5 +1,6 @@
1
1
  import FormData from 'form-data';
2
2
  import { Paginated, RequestParameter } from '../data.interface';
3
+ import { TokenOption } from '../http.service';
3
4
  import { Asset, AssetRevision, Attachment, EventCause, EventLevelOverride } from '../interfaces';
4
5
  import { AssetService } from '../services';
5
6
  import { APIBaseMock } from './api-base.mock';
@@ -27,5 +28,7 @@ export declare class AssetMockService extends BaseService implements AssetServic
27
28
  getRevisions(assetId: string): Promise<Paginated<AssetRevision[]>>;
28
29
  rollback(assetId: string, revisionId: string): Promise<Asset>;
29
30
  deleteRevision(assetId: string, revisionId: string): Promise<any>;
31
+ findOneExternal(key: string, options?: TokenOption): Promise<Asset>;
32
+ updateOneExternal(key: string, dto: any, options?: TokenOption): Promise<Asset>;
30
33
  }
31
34
  export {};
@@ -111,5 +111,14 @@ class AssetMockService extends BaseService {
111
111
  this.revisions.splice(index, 1);
112
112
  return Promise.resolve(revisionId);
113
113
  }
114
+ findOneExternal(key, options) {
115
+ return Promise.resolve(this.data.find((asset) => asset.externalKey === key));
116
+ }
117
+ async updateOneExternal(key, dto, options) {
118
+ const asset = await this.findOneExternal(key, options);
119
+ const index = this.data.findIndex((asset) => asset.externalKey === key);
120
+ this.data[index] = { ...asset, ...dto };
121
+ return Promise.resolve(this.data[index]);
122
+ }
114
123
  }
115
124
  exports.AssetMockService = AssetMockService;
@@ -78,8 +78,9 @@ class ContentMockService extends BaseService {
78
78
  const page = this.getItems(params, false);
79
79
  return Promise.resolve(page);
80
80
  }
81
- upload(form) {
82
- return Promise.resolve(undefined);
81
+ async upload(form) {
82
+ const content = await this.addOne({});
83
+ return Promise.resolve(content);
83
84
  }
84
85
  }
85
86
  exports.ContentMockService = ContentMockService;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DataMockService = void 0;
4
+ const crypto_1 = require("crypto");
4
5
  const data_interface_1 = require("../data.interface");
5
6
  const data_service_1 = require("../data.service");
6
7
  class DataMockService extends data_service_1.DataService {
@@ -13,8 +14,9 @@ class DataMockService extends data_service_1.DataService {
13
14
  return Promise.all(map);
14
15
  }
15
16
  addOne(dto) {
16
- this.data.push(dto);
17
- return Promise.resolve(dto);
17
+ const dtoWithId = { id: (0, crypto_1.randomUUID)(), ...dto };
18
+ this.data.push(dtoWithId);
19
+ return Promise.resolve(dtoWithId);
18
20
  }
19
21
  deleteOne(id) {
20
22
  const index = this.data.findIndex((v) => v.id === id);
@@ -1,9 +1,9 @@
1
- import { Method } from 'axios';
1
+ import { AxiosInstance, Method } from 'axios';
2
2
  import { Config, HttpClient, Issuer, TokenOption } from '../http.service';
3
3
  import { TokenSet } from '../token-set';
4
4
  export declare class HttpMockService extends HttpClient {
5
- protected readonly authAxiosInstance: any;
6
- protected readonly axiosInstance: any;
5
+ protected readonly authAxiosInstance: AxiosInstance;
6
+ protected readonly axiosInstance: AxiosInstance;
7
7
  constructor();
8
8
  delete: <T>(_url: string, _config: Config | undefined) => Promise<T>;
9
9
  get: <T>(_url: string, _config: Config | undefined) => Promise<T>;
@@ -20,5 +20,7 @@ export declare class AssetService extends BaseService {
20
20
  getRevisions(assetId: string, options?: TokenOption): Promise<Paginated<AssetRevision[]>>;
21
21
  rollback(assetId: string, revisionId: string, options?: TokenOption): Promise<Asset>;
22
22
  deleteRevision(assetId: string, revisionId: string, options?: TokenOption): Promise<any>;
23
+ findOneExternal(key: string, options?: TokenOption): Promise<Asset>;
24
+ updateOneExternal(key: string, dto: any, options?: TokenOption): Promise<Asset>;
23
25
  }
24
26
  export {};
@@ -34,13 +34,10 @@ class AssetService extends BaseService {
34
34
  return this.httpClient.get(`${this.basePath}/${assetId}/attachments`, options);
35
35
  }
36
36
  getEventLevelOverride(ids, causes, options = {}) {
37
- return this.httpClient.get(`${this.basePath}/eventcauses`, {
38
- params: { ids: ids.join(','), causes: causes.join(',') },
39
- ...options,
40
- });
37
+ return this.httpClient.post(`${this.basePath}/event-causes`, { ids, causes }, options);
41
38
  }
42
39
  updateEventCausesAsset(id, dto, options = {}) {
43
- return this.httpClient.put(`${this.basePath}/${id}/eventcauses`, dto, options);
40
+ return this.httpClient.put(`${this.basePath}/${id}/event-causes`, dto, options);
44
41
  }
45
42
  getRevisions(assetId, options = {}) {
46
43
  return this.httpClient.get(`${this.basePath}/${assetId}/revisions`, options);
@@ -51,5 +48,11 @@ class AssetService extends BaseService {
51
48
  deleteRevision(assetId, revisionId, options = {}) {
52
49
  return this.httpClient.delete(`${this.basePath}/${assetId}/revisions/${revisionId}`, options);
53
50
  }
51
+ findOneExternal(key, options = {}) {
52
+ return this.httpClient.get(`${this.basePath}/external/${key}`, options);
53
+ }
54
+ updateOneExternal(key, dto, options = {}) {
55
+ return this.httpClient.put(`${this.basePath}/external/${key}`, dto, options);
56
+ }
54
57
  }
55
58
  exports.AssetService = AssetService;