kuzzle-device-manager-types 3.0.0-3-dev.20 → 3.0.0-3-dev.21

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 (27) hide show
  1. package/dist/lib/modules/asset/AssetService.d.ts +6 -0
  2. package/dist/lib/modules/asset/roles/RoleAssetsAdmin.d.ts +1 -0
  3. package/dist/lib/modules/asset/roles/RoleAssetsReader.d.ts +1 -0
  4. package/dist/lib/modules/device/roles/RoleDevicesAdmin.d.ts +1 -0
  5. package/dist/lib/modules/device/roles/RoleDevicesReader.d.ts +1 -0
  6. package/dist/lib/modules/group/GroupsService.d.ts +5 -0
  7. package/dist/lib/modules/group/index.d.ts +1 -0
  8. package/dist/lib/modules/group/roles/RoleGroupsAdmin.d.ts +1 -0
  9. package/dist/lib/modules/group/roles/RoleGroupsReader.d.ts +1 -0
  10. package/dist/lib/modules/group/types/GroupEvents.d.ts +8 -0
  11. package/dist/lib/modules/model/MetadataReferential.d.ts +119 -0
  12. package/dist/lib/modules/model/ModelService.d.ts +103 -1
  13. package/dist/lib/modules/model/ModelsConflicts.d.ts +23 -0
  14. package/dist/lib/modules/model/ModelsController.d.ts +11 -2
  15. package/dist/lib/modules/model/ModelsRegister.d.ts +33 -1
  16. package/dist/lib/modules/model/types/ModelApi.d.ts +93 -2
  17. package/dist/lib/modules/model/types/ModelContent.d.ts +67 -1
  18. package/dist/lib/modules/model/types/ModelDefinition.d.ts +6 -3
  19. package/dist/lib/modules/model/types/ModelEvents.d.ts +6 -1
  20. package/dist/lib/modules/plugin/DeviceManagerEngine.d.ts +33 -0
  21. package/dist/lib/modules/plugin/DeviceManagerPlugin.d.ts +36 -1
  22. package/dist/lib/modules/plugin/types/DeviceManagerConfiguration.d.ts +11 -0
  23. package/dist/lib/modules/shared/utils/lock.d.ts +7 -1
  24. package/dist/tests/application/assets/Pole.d.ts +5 -0
  25. package/dist/tests/application/assets/index.d.ts +1 -0
  26. package/dist/tests/application/metadata.d.ts +5 -0
  27. package/package.json +1 -1
@@ -58,4 +58,10 @@ export declare class AssetService extends DigitalTwinService {
58
58
  [locale: string]: string;
59
59
  }, index: string, request: KuzzleRequest): Promise<KDocument<AssetContent>>;
60
60
  private refreshModel;
61
+ /**
62
+ * Lists the engines whose assets use the given model:
63
+ * the model indexes for a tenant-scoped model, every engine for a commons model,
64
+ * and the engines of the model tenantClasses otherwise.
65
+ */
66
+ private getModelEngines;
61
67
  }
@@ -18,6 +18,7 @@ import { KuzzleRole } from "../../shared/types/KuzzleRole";
18
18
  getAsset: true,
19
19
  writeAsset: true,
20
20
  listMeasures: true,
21
+ getMetadataReferential: true,
21
22
  },
22
23
  },
23
24
  */
@@ -22,6 +22,7 @@ import { KuzzleRole } from "../../shared/types/KuzzleRole";
22
22
  listAssets: true,
23
23
  listMeasures: true,
24
24
  getAsset: true,
25
+ getMetadataReferential: true,
25
26
  },
26
27
  },
27
28
  */
@@ -25,6 +25,7 @@ import { KuzzleRole } from "../../shared/types/KuzzleRole";
25
25
  getDevice: true,
26
26
  writeDevice: true,
27
27
  listMeasures: true,
28
+ getMetadataReferential: true,
28
29
  },
29
30
  },
30
31
  */
@@ -22,6 +22,7 @@ import { KuzzleRole } from "../../shared/types/KuzzleRole";
22
22
  listDevices: true,
23
23
  getDevice: true,
24
24
  listMeasures: true,
25
+ getMetadataReferential: true,
25
26
  },
26
27
  },
27
28
  }
@@ -9,6 +9,11 @@ import { KuzzleLogger } from "kuzzle-logger";
9
9
  export declare class GroupsService extends BaseService {
10
10
  readonly logger: KuzzleLogger;
11
11
  constructor(plugin: DeviceManagerPlugin, logger: KuzzleLogger);
12
+ /**
13
+ * Refreshes the metadata of the groups of a model, in every engine of the model scope:
14
+ * added metadata are set to their default value, removed metadata are deleted.
15
+ */
16
+ private refreshModel;
12
17
  create(_id: string, index: string, metadata: JSONObject, model: string, name: string, path: string, request: KuzzleRequest): Promise<KDocument<GroupContent>>;
13
18
  get(index: string, _id: string, request: KuzzleRequest): Promise<import("kuzzle").KDocument<GroupContent>>;
14
19
  update(request: KuzzleRequest, _id: string, index: string, name?: string, metadata?: Metadata): Promise<import("kuzzle").KDocument<GroupContent>>;
@@ -2,3 +2,4 @@ export * from "./collections/groupsMappings";
2
2
  export * from "./GroupsModule";
3
3
  export * from "./roles/RoleGroupsAdmin";
4
4
  export * from "./roles/RoleGroupsReader";
5
+ export * from "./types/GroupEvents";
@@ -18,6 +18,7 @@ import { KuzzleRole } from "../../shared/types/KuzzleRole";
18
18
  getAsset: true,
19
19
  writeAsset: true,
20
20
  listMeasures: true,
21
+ getMetadataReferential: true,
21
22
  },
22
23
  },
23
24
  */
@@ -18,6 +18,7 @@ import { KuzzleRole } from "../../shared/types/KuzzleRole";
18
18
  getAsset: true,
19
19
  writeAsset: true,
20
20
  listMeasures: true,
21
+ getMetadataReferential: true,
21
22
  },
22
23
  },
23
24
  */
@@ -0,0 +1,8 @@
1
+ import { GroupModelContent } from "../../model/types/ModelContent";
2
+ export type AskGroupRefreshModel = {
3
+ name: "ask:device-manager:group:refresh-model";
4
+ payload: {
5
+ groupModel: GroupModelContent;
6
+ };
7
+ result: void;
8
+ };
@@ -0,0 +1,119 @@
1
+ import { EmbeddedSDK } from "kuzzle";
2
+ import { JSONObject, KDocument } from "kuzzle-sdk";
3
+ import { ConflictChunk } from "./ModelsConflicts";
4
+ import { AssetModelContent, DeviceModelContent, GroupModelContent, MetadataDetails, MetadataMappings, MetadataReferential, MetadataReferentialContent, MetadataReferentialEntry, ReferentialMetadataMapping, ResolvedMetadataMappings } from "./types/ModelContent";
5
+ export declare const METADATA_REFERENTIAL_ID = "model-metadata-referential";
6
+ /**
7
+ * Runs cb holding the metadata referential lock, taken by every write of the referential
8
+ * and of asset, device and group models, so their conflicts checks see each other writes
9
+ */
10
+ export declare function withMetadataReferentialLock<T>(cb: () => Promise<T>): Promise<T>;
11
+ export type MetadataModelContent = AssetModelContent | DeviceModelContent | GroupModelContent;
12
+ export type MetadataModelType = MetadataModelContent["type"];
13
+ /**
14
+ * Metadata related fields of an asset, device or group model
15
+ */
16
+ export type ModelMetadataFields = {
17
+ metadataMappings: MetadataMappings;
18
+ defaultMetadata: JSONObject;
19
+ metadataDetails: MetadataDetails;
20
+ };
21
+ export type MetadataResolutionContext = {
22
+ modelType: MetadataModelType;
23
+ model: string;
24
+ /**
25
+ * Builds the error thrown on an invalid use of the referential.
26
+ * PluginImplementationError when registering from code, BadRequestError from the API.
27
+ */
28
+ createError: (message: string) => Error;
29
+ };
30
+ export type MetadataEnrichment = {
31
+ /**
32
+ * Metadata fields to store: referential markers are kept in metadataMappings,
33
+ * metadataDetails and defaultMetadata are enriched with the referential values
34
+ */
35
+ fields: ModelMetadataFields;
36
+ /**
37
+ * Metadata mappings with the referential markers replaced by the referential mappings
38
+ */
39
+ resolvedMappings: ResolvedMetadataMappings;
40
+ /**
41
+ * Inline metadata identical to a referential entry, which should use the referential instead
42
+ */
43
+ warnings: string[];
44
+ };
45
+ /**
46
+ * @returns true if the metadata mappings mark a metadata of the referential
47
+ */
48
+ export declare function isReferentialMapping(mapping: unknown): mapping is ReferentialMetadataMapping;
49
+ /**
50
+ * Lists the metadata of a model coming from the metadata referential
51
+ */
52
+ export declare function getReferentialNames(metadataMappings?: MetadataMappings): string[];
53
+ /**
54
+ * Replaces the referential markers of metadata mappings by the referential mappings.
55
+ * A marker of a metadata missing from the referential is dropped.
56
+ */
57
+ export declare function resolveMetadataMappings(referential: MetadataReferential, metadataMappings?: MetadataMappings): ResolvedMetadataMappings;
58
+ /**
59
+ * @returns The model with the referential markers of its metadata mappings resolved
60
+ */
61
+ export declare function resolveModelMappings<T extends MetadataModelContent>(referential: MetadataReferential, content: T): T;
62
+ /**
63
+ * Resolves the referential metadata of a stored model, to be read:
64
+ * the markers are replaced by the referential mappings, the details and default values
65
+ * are merged over the current referential values.
66
+ * A marker of a metadata missing from the referential is dropped.
67
+ *
68
+ * @returns The model with its referential metadata resolved
69
+ */
70
+ export declare function resolveModelMetadata<T extends MetadataModelContent>(referential: MetadataReferential, content: T): T;
71
+ /**
72
+ * Validates the shape of a metadata referential entry
73
+ *
74
+ * @throws The error built by createError if the entry is invalid
75
+ */
76
+ export declare function checkMetadataReferentialEntry(name: string, entry: MetadataReferentialEntry, createError: (message: string) => Error): void;
77
+ /**
78
+ * Validates the metadata mappings of a model against the metadata referential and enriches
79
+ * the details and default values of the metadata coming from the referential.
80
+ *
81
+ * A metadata of the referential is marked `{ referential: true }` in metadataMappings, the marker is kept.
82
+ * Its details are the referential locales (merged per locale), editorHint and icon, overridden by the
83
+ * model ones. Its default value is the referential one, unless the model defines one.
84
+ *
85
+ * An inline metadata with the name of a referential entry must have the same mappings (legacy).
86
+ *
87
+ * @throws The error built by createError on an invalid marker or an unknown metadata
88
+ * @throws MappingsConflictsError if an inline metadata conflicts with the referential
89
+ */
90
+ export declare function enrichModelMetadata(referential: MetadataReferential, fields: Partial<ModelMetadataFields>, context: MetadataResolutionContext): MetadataEnrichment;
91
+ /**
92
+ * Lists the conflicts between a referential entry and the inline metadata of the same name of models
93
+ */
94
+ export declare function getEntryModelsConflicts(name: string, entry: MetadataReferentialEntry, models: MetadataModelContent[]): ConflictChunk[];
95
+ /**
96
+ * Lists the inline metadata a model write adds: metadataMappings keys that neither
97
+ * use the referential nor are already defined inline by the stored model.
98
+ */
99
+ export declare function getAddedInlineMetadata(metadataMappings: MetadataMappings, stored: MetadataModelContent | null): string[];
100
+ /**
101
+ * Reads the metadata referential document
102
+ *
103
+ * @returns The referential metadata, empty if the document does not exist yet
104
+ */
105
+ export declare function fetchMetadataReferential(sdk: EmbeddedSDK, platformIndex: string): Promise<MetadataReferential>;
106
+ /**
107
+ * Writes the whole metadata referential document
108
+ */
109
+ export declare function saveMetadataReferential(sdk: EmbeddedSDK, platformIndex: string, referential: MetadataReferential): Promise<import("kuzzle").KDocument<MetadataReferentialContent>>;
110
+ /**
111
+ * Lists every stored asset, device and group model
112
+ */
113
+ export declare function fetchMetadataModels(sdk: EmbeddedSDK, platformIndex: string): Promise<KDocument<MetadataModelContent>[]>;
114
+ /**
115
+ * Lists every stored asset, device and group model using the given metadata of the referential.
116
+ *
117
+ * metadataMappings is not indexed, the filtering is done after fetching the models.
118
+ */
119
+ export declare function fetchReferencingModels(sdk: EmbeddedSDK, platformIndex: string, name: string): Promise<KDocument<MetadataModelContent>[]>;
@@ -2,11 +2,36 @@ import { KuzzleRequest } from "kuzzle";
2
2
  import { JSONObject, KDocument, KHit, SearchResult } from "kuzzle-sdk";
3
3
  import { DeviceManagerPlugin } from "../plugin";
4
4
  import { BaseService, SearchParams } from "../shared";
5
- import { AssetModelContent, DeviceModelContent, GroupModelContent, LocaleDetails, MeasureModelContent, MetadataDetails, MetadataGroups, MetadataMappings, TooltipModels } from "./types/ModelContent";
5
+ import { AssetModelContent, DeviceModelContent, GroupModelContent, LocaleDetails, MeasureModelContent, MetadataDetails, MetadataGroups, MetadataMappings, MetadataReferential, MetadataReferentialEntry, TooltipModels } from "./types/ModelContent";
6
6
  import { SchemaObject } from "ajv";
7
7
  import { MeasureValuesDetails } from "../measure";
8
8
  import { NamedMeasures } from "../decoder";
9
9
  import { KuzzleLogger } from "kuzzle-logger";
10
+ import { MetadataModelContent } from "./MetadataReferential";
11
+ /**
12
+ * Fields of a group model update.
13
+ * Affinity and icon are kept when omitted.
14
+ */
15
+ export type GroupModelUpdate = {
16
+ affinity?: JSONObject;
17
+ defaultMetadata: JSONObject;
18
+ icon?: string;
19
+ locales: {
20
+ [valueName: string]: LocaleDetails;
21
+ };
22
+ metadataDetails: MetadataDetails;
23
+ metadataGroups: MetadataGroups;
24
+ metadataMappings: MetadataMappings;
25
+ };
26
+ /**
27
+ * Fields of a device model update.
28
+ * Metadata details and default values are kept when omitted.
29
+ */
30
+ export type DeviceModelUpdate = {
31
+ defaultMetadata?: JSONObject;
32
+ metadataDetails?: MetadataDetails;
33
+ metadataMappings: MetadataMappings;
34
+ };
10
35
  export declare class ModelService extends BaseService {
11
36
  readonly logger: KuzzleLogger;
12
37
  constructor(plugin: DeviceManagerPlugin, logger: KuzzleLogger);
@@ -66,4 +91,81 @@ export declare class ModelService extends BaseService {
66
91
  updateAsset(tenantClasses: string[], index: string | undefined, model: string, metadataMappings: MetadataMappings, defaultMetadata: JSONObject, metadataDetails: MetadataDetails, metadataGroups: MetadataGroups, measures: AssetModelContent["asset"]["measures"], tooltipModels: TooltipModels, locales: {
67
92
  [valueName: string]: LocaleDetails;
68
93
  }, icon: string | undefined, request: KuzzleRequest): Promise<KDocument<AssetModelContent>>;
94
+ /**
95
+ * Adds metadata of the metadata referential to a device model.
96
+ *
97
+ * Device models are additive only from the API: every existing metadata must be kept unchanged,
98
+ * new metadata must come from the referential. Metadata details and default values can change.
99
+ * The engines mappings are updated and the devices get the new metadata with their default value.
100
+ *
101
+ * @throws BadRequestError if an existing metadata is missing or changed, or a new one is inline
102
+ * @throws MappingsConflictsError if the new metadata conflict with the existing mappings
103
+ */
104
+ updateDevice(model: string, { defaultMetadata, metadataDetails, metadataMappings }: DeviceModelUpdate): Promise<KDocument<DeviceModelContent>>;
105
+ /**
106
+ * Returns the group model available for the given tenant classes:
107
+ * a model of these classes first, then a commons model.
108
+ *
109
+ * @throws NotFoundError if no group model with this name is available
110
+ */
111
+ private getScopedGroup;
112
+ /**
113
+ * Updates a group model, keeping its scope.
114
+ * Affinity and icon are kept when omitted.
115
+ *
116
+ * The engines mappings are updated and the groups of the model are refreshed.
117
+ *
118
+ * @throws MappingsConflictsError if the new mappings conflict with the existing ones
119
+ */
120
+ updateGroup(tenantClasses: string[], model: string, { affinity, defaultMetadata, icon, locales, metadataDetails, metadataGroups, metadataMappings, }: GroupModelUpdate): Promise<KDocument<GroupModelContent>>;
121
+ /**
122
+ * Validates the metadata of a model written through the API against the metadata referential
123
+ * and enriches the details and default values of the metadata coming from it
124
+ */
125
+ private resolveMetadata;
126
+ /**
127
+ * Resolves the referential metadata of stored models, to be returned by the API
128
+ */
129
+ resolveModels<D extends {
130
+ _source: MetadataModelContent;
131
+ }>(documents: D[]): Promise<D[]>;
132
+ getMetadataReferential(): Promise<MetadataReferential>;
133
+ /**
134
+ * Creates a metadata of the metadata referential, or updates its details.
135
+ *
136
+ * The mappings of a new metadata are merged into the assets, devices and groups collections
137
+ * of every engine. They cannot be modified afterwards: only the locales, editor hint,
138
+ * default value and icon of an existing metadata can change. These are copied into the models
139
+ * using the metadata when they are written, the existing models are not modified.
140
+ *
141
+ * @throws BadRequestError if the mappings of an existing metadata are modified
142
+ * @throws MappingsConflictsError if the new metadata conflicts with an inline metadata of a model
143
+ * or with the actual mappings of an engine collection
144
+ */
145
+ writeMetadata(name: string, definition: MetadataReferentialEntry): Promise<MetadataReferential>;
146
+ /**
147
+ * Deletes a metadata of the metadata referential.
148
+ * Its mappings stay in the engines collections, Elasticsearch cannot remove them.
149
+ *
150
+ * @throws BadRequestError if a model still uses the metadata
151
+ */
152
+ deleteMetadata(name: string): Promise<MetadataReferential>;
153
+ /**
154
+ * With the referentialOnly option, rejects the inline metadata a model write adds.
155
+ * The inline metadata already defined by the stored model are kept (legacy).
156
+ *
157
+ * @throws BadRequestError if new inline metadata are added
158
+ */
159
+ private checkReferentialOnly;
160
+ /**
161
+ * Updates the engines collections. If Elasticsearch rejects the new mappings, the model is
162
+ * restored to its previous version (or deleted if it is new), otherwise every next engines
163
+ * update would fail on it.
164
+ */
165
+ private updateEnginesOrRestore;
166
+ private getStoredModel;
167
+ /**
168
+ * @throws BadRequestError if the metadata is registered from code
169
+ */
170
+ private checkUnmanagedMetadata;
69
171
  }
@@ -36,3 +36,26 @@ export declare function getGroupConflicts(measures: GroupModelContent[], additio
36
36
  * @returns An array of ConflictChunk between current measures and the new measure
37
37
  */
38
38
  export declare function getMeasureConflicts(measures: MeasureModelContent[], additional: MeasureModelContent): ConflictChunk[];
39
+ /**
40
+ * Find every conflicts between two sets of fields mappings (name => field mappings),
41
+ * e.g. metadata mappings or the metadata properties of an ES collection.
42
+ *
43
+ * Unlike findConflicts, a field defined with a type on one side and with properties on the other
44
+ * is a conflict, Elasticsearch cannot change a field from a value to an object or the opposite.
45
+ * Fields defined on one side only are not conflicts.
46
+ *
47
+ * @param currentMappings The current fields mappings
48
+ * @param newMappings The new fields mappings
49
+ * @param basePath Optional path to be added before conflicts paths
50
+ * @returns An array of MappingsConflict
51
+ */
52
+ export declare function findMappingsConflicts(currentMappings: any, newMappings: any, basePath?: string): MappingsConflict[];
53
+ /**
54
+ * Find every conflicts between two objects.
55
+ * WARNING: "undefined" type of conflicts are not registered
56
+ * @param sourceObject The source object used to compare
57
+ * @param objectToCompare The target object to compare to
58
+ * @param basePath Optional path to be added before conflicts paths
59
+ * @returns An array of MappingsConflict
60
+ */
61
+ export declare function findConflicts(sourceObject: any, objectToCompare: any, basePath?: string): MappingsConflict[];
@@ -1,6 +1,6 @@
1
1
  import { ControllerDefinition, KuzzleRequest } from "kuzzle";
2
2
  import { ModelService } from "./ModelService";
3
- import { ApiModelWriteAssetResult, ApiModelWriteDeviceResult, ApiModelWriteMeasureResult, ApiModelUpdateAssetResult, ApiModelDeleteAssetResult, ApiModelDeleteDeviceResult, ApiModelDeleteMeasureResult, ApiModelListAssetsResult, ApiModelListDevicesResult, ApiModelListMeasuresResult, ApiModelGetAssetResult, ApiModelGetDeviceResult, ApiModelGetMeasureResult, ApiModelSearchAssetsResult, ApiModelSearchDevicesResult, ApiModelSearchMeasuresResult, ApiModelDeleteGroupResult, ApiModelGetGroupResult, ApiModelListGroupsResult, ApiModelSearchGroupsResult, ApiModelWriteGroupResult } from "./types/ModelApi";
3
+ import { ApiModelWriteAssetResult, ApiModelWriteDeviceResult, ApiModelWriteMeasureResult, ApiModelUpdateAssetResult, ApiModelDeleteAssetResult, ApiModelDeleteDeviceResult, ApiModelDeleteMeasureResult, ApiModelListAssetsResult, ApiModelListDevicesResult, ApiModelListMeasuresResult, ApiModelGetAssetResult, ApiModelGetDeviceResult, ApiModelGetMeasureResult, ApiModelSearchAssetsResult, ApiModelSearchDevicesResult, ApiModelSearchMeasuresResult, ApiModelDeleteGroupResult, ApiModelGetGroupResult, ApiModelListGroupsResult, ApiModelSearchGroupsResult, ApiModelWriteGroupResult, ApiModelUpdateGroupResult, ApiModelUpdateDeviceResult, ApiModelGetMetadataReferentialResult, ApiModelWriteMetadataResult, ApiModelDeleteMetadataResult } from "./types/ModelApi";
4
4
  import { KuzzleLogger } from "kuzzle-logger";
5
5
  export declare class ModelsController {
6
6
  private modelService;
@@ -20,7 +20,7 @@ export declare class ModelsController {
20
20
  deleteGroup(request: KuzzleRequest): Promise<ApiModelDeleteGroupResult>;
21
21
  deleteMeasure(request: KuzzleRequest): Promise<ApiModelDeleteMeasureResult>;
22
22
  listAssets(request: KuzzleRequest): Promise<ApiModelListAssetsResult>;
23
- listDevices(): Promise<ApiModelListDevicesResult>;
23
+ listDevices(request: KuzzleRequest): Promise<ApiModelListDevicesResult>;
24
24
  listGroups(request: KuzzleRequest): Promise<ApiModelListGroupsResult>;
25
25
  listMeasures(request: KuzzleRequest): Promise<ApiModelListMeasuresResult>;
26
26
  searchAssets(request: KuzzleRequest): Promise<ApiModelSearchAssetsResult>;
@@ -28,4 +28,13 @@ export declare class ModelsController {
28
28
  searchGroups(request: KuzzleRequest): Promise<ApiModelSearchGroupsResult>;
29
29
  searchMeasures(request: KuzzleRequest): Promise<ApiModelSearchMeasuresResult>;
30
30
  updateAsset(request: KuzzleRequest): Promise<ApiModelUpdateAssetResult>;
31
+ updateDevice(request: KuzzleRequest): Promise<ApiModelUpdateDeviceResult>;
32
+ updateGroup(request: KuzzleRequest): Promise<ApiModelUpdateGroupResult>;
33
+ /**
34
+ * Resolves the referential metadata of models, unless the rawModel flag is set
35
+ */
36
+ private resolveModels;
37
+ getMetadataReferential(): Promise<ApiModelGetMetadataReferentialResult>;
38
+ writeMetadata(request: KuzzleRequest): Promise<ApiModelWriteMetadataResult>;
39
+ deleteMetadata(request: KuzzleRequest): Promise<ApiModelDeleteMetadataResult>;
31
40
  }
@@ -1,7 +1,7 @@
1
1
  import { DeviceManagerPlugin } from "../plugin";
2
2
  import { NamedMeasures } from "../decoder";
3
3
  import { MeasureDefinition } from "../measure";
4
- import { GroupAffinity, LocaleDetails, MetadataDetails, MetadataGroups, MetadataMappings, TooltipModels } from "./types/ModelContent";
4
+ import { GroupAffinity, LocaleDetails, MetadataDetails, MetadataGroups, MetadataMappings, MetadataReferentialEntry, TooltipModels } from "./types/ModelContent";
5
5
  import { JSONObject } from "kuzzle-sdk";
6
6
  export declare class ModelsRegister {
7
7
  private config;
@@ -10,10 +10,42 @@ export declare class ModelsRegister {
10
10
  private deviceModels;
11
11
  private groupModels;
12
12
  private measureModels;
13
+ private metadataReferential;
13
14
  private logger;
14
15
  private get sdk();
15
16
  init(plugin: DeviceManagerPlugin): void;
16
17
  loadModels(): Promise<void>;
18
+ /**
19
+ * Merges the metadata registered from code over the stored metadata referential and saves it.
20
+ * Metadata added through the API are kept, the details of metadata registered from code win.
21
+ *
22
+ * @throws PluginImplementationError if the mappings of a stored metadata are modified, or if a new
23
+ * metadata conflicts with the stored models or the engines collections mappings
24
+ */
25
+ private loadMetadataReferential;
26
+ /**
27
+ * Checks the metadata registered from code that are not in the stored referential yet
28
+ * against the inline metadata of the stored models and the engines collections mappings
29
+ *
30
+ * @throws PluginImplementationError on a conflict
31
+ */
32
+ private checkNewMetadata;
33
+ /**
34
+ * Validates the metadata of models registered from code against the metadata referential
35
+ * and enriches the details and default values of the metadata coming from it
36
+ */
37
+ private resolveModels;
38
+ /**
39
+ * Registers a metadata in the metadata referential.
40
+ * Asset, device and group models can then use it with `{ referential: true }` in their metadataMappings.
41
+ * Its mappings cannot be modified once loaded, they are merged into the engines collections.
42
+ * Registering again an identical definition is allowed, so several modules can share a metadata.
43
+ *
44
+ * @param name - Name of the metadata
45
+ * @param definition - Mappings, default translations, editor hint, default value and icon of the metadata
46
+ * @throws PluginImplementationError if the metadata is invalid or already registered with another definition
47
+ */
48
+ registerMetadata(name: string, definition: MetadataReferentialEntry): void;
17
49
  /**
18
50
  * Registers an asset model.
19
51
  *
@@ -1,5 +1,5 @@
1
1
  import { JSONObject, KDocument, KHit, SearchResult } from "kuzzle-sdk";
2
- import { AssetModelContent, DeviceModelContent, GroupAffinity, GroupModelContent, LocaleDetails, MeasureModelContent, MetadataDetails, MetadataGroups, MetadataMappings, TooltipModels } from "./ModelContent";
2
+ import { AssetModelContent, DeviceModelContent, GroupAffinity, GroupModelContent, LocaleDetails, MeasureModelContent, MetadataDetails, MetadataGroups, MetadataMappings, MetadataReferential, MetadataReferentialEntry, TooltipModels } from "./ModelContent";
3
3
  import { SchemaObject } from "ajv";
4
4
  import { MeasureValuesDetails } from "../../measure/types/MeasureDefinition";
5
5
  interface ModelsControllerRequest {
@@ -9,16 +9,28 @@ export interface ApiModelGetAssetRequest extends ModelsControllerRequest {
9
9
  action: "getAsset";
10
10
  model: string;
11
11
  tenantClasses: string[];
12
+ /**
13
+ * Returns the stored model, without resolving its referential metadata
14
+ */
15
+ rawModel?: boolean;
12
16
  }
13
17
  export type ApiModelGetAssetResult = KDocument<AssetModelContent>;
14
18
  export interface ApiModelGetDeviceRequest extends ModelsControllerRequest {
15
19
  action: "getDevice";
16
20
  model: string;
21
+ /**
22
+ * Returns the stored model, without resolving its referential metadata
23
+ */
24
+ rawModel?: boolean;
17
25
  }
18
26
  export type ApiModelGetDeviceResult = KDocument<DeviceModelContent>;
19
27
  export interface ApiModelGetGroupRequest extends ModelsControllerRequest {
20
28
  action: "getGroup";
21
29
  model: string;
30
+ /**
31
+ * Returns the stored model, without resolving its referential metadata
32
+ */
33
+ rawModel?: boolean;
22
34
  }
23
35
  export type ApiModelGetGroupResult = KDocument<GroupModelContent>;
24
36
  export interface ApiModelGetMeasureRequest extends ModelsControllerRequest {
@@ -30,7 +42,10 @@ export type ApiModelGetMeasureResult = KDocument<MeasureModelContent>;
30
42
  export interface ApiModelWriteAssetRequest extends ModelsControllerRequest {
31
43
  action: "writeAsset";
32
44
  body: {
33
- tenantClasses: string[];
45
+ /**
46
+ * Mutually exclusive with `indexes`
47
+ */
48
+ tenantClasses?: string[];
34
49
  indexes?: string[];
35
50
  model: string;
36
51
  icon?: string;
@@ -76,6 +91,43 @@ export interface ApiModelWriteGroupRequest extends ModelsControllerRequest {
76
91
  };
77
92
  }
78
93
  export type ApiModelWriteGroupResult = KDocument<GroupModelContent>;
94
+ export interface ApiModelUpdateDeviceRequest extends ModelsControllerRequest {
95
+ action: "updateDevice";
96
+ model: string;
97
+ body: {
98
+ /**
99
+ * Full set of metadata mappings: the existing ones, unchanged, and the new ones,
100
+ * which must be metadata of the referential (`{ referential: true }`)
101
+ */
102
+ metadataMappings: MetadataMappings;
103
+ /**
104
+ * Replaces the metadata details when present
105
+ */
106
+ metadataDetails?: MetadataDetails;
107
+ /**
108
+ * Replaces the default values when present
109
+ */
110
+ defaultValues?: JSONObject;
111
+ };
112
+ }
113
+ export type ApiModelUpdateDeviceResult = KDocument<DeviceModelContent>;
114
+ export interface ApiModelUpdateGroupRequest extends ModelsControllerRequest {
115
+ action: "updateGroup";
116
+ tenantClasses?: string[];
117
+ model: string;
118
+ body: {
119
+ affinity?: GroupAffinity;
120
+ icon?: string;
121
+ metadataDetails?: MetadataDetails;
122
+ metadataGroups?: MetadataGroups;
123
+ metadataMappings?: MetadataMappings;
124
+ defaultValues?: JSONObject;
125
+ locales?: {
126
+ [valueName: string]: LocaleDetails;
127
+ };
128
+ };
129
+ }
130
+ export type ApiModelUpdateGroupResult = KDocument<GroupModelContent>;
79
131
  export interface ApiModelWriteMeasureRequest extends ModelsControllerRequest {
80
132
  action: "writeMeasure";
81
133
  body: {
@@ -132,6 +184,10 @@ export type ApiModelDeleteMeasureResult = void;
132
184
  export interface ApiModelListAssetsRequest extends ModelsControllerRequest {
133
185
  action: "listAssets";
134
186
  tenantClasses: string[];
187
+ /**
188
+ * Returns the stored model, without resolving its referential metadata
189
+ */
190
+ rawModel?: boolean;
135
191
  }
136
192
  export type ApiModelListAssetsResult = {
137
193
  models: KDocument<AssetModelContent>[];
@@ -139,6 +195,10 @@ export type ApiModelListAssetsResult = {
139
195
  };
140
196
  export interface ApiModelListDevicesRequest extends ModelsControllerRequest {
141
197
  action: "listDevices";
198
+ /**
199
+ * Returns the stored model, without resolving its referential metadata
200
+ */
201
+ rawModel?: boolean;
142
202
  }
143
203
  export type ApiModelListDevicesResult = {
144
204
  models: KDocument<DeviceModelContent>[];
@@ -147,6 +207,10 @@ export type ApiModelListDevicesResult = {
147
207
  export interface ApiModelListGroupsRequest extends ModelsControllerRequest {
148
208
  action: "listGroups";
149
209
  tenantClasses: string[];
210
+ /**
211
+ * Returns the stored model, without resolving its referential metadata
212
+ */
213
+ rawModel?: boolean;
150
214
  }
151
215
  export type ApiModelListGroupsResult = {
152
216
  models: KDocument<GroupModelContent>[];
@@ -163,6 +227,10 @@ export type ApiModelListMeasuresResult = {
163
227
  export interface ApiModelSearchAssetsRequest extends ModelsControllerRequest {
164
228
  action: "searchAssets";
165
229
  tenantClasses: string[];
230
+ /**
231
+ * Returns the stored model, without resolving its referential metadata
232
+ */
233
+ rawModel?: boolean;
166
234
  from?: number;
167
235
  size?: number;
168
236
  scrollTTL?: string;
@@ -171,6 +239,10 @@ export interface ApiModelSearchAssetsRequest extends ModelsControllerRequest {
171
239
  export type ApiModelSearchAssetsResult = SearchResult<KHit<AssetModelContent>>;
172
240
  export interface ApiModelSearchDevicesRequest extends ModelsControllerRequest {
173
241
  action: "searchDevices";
242
+ /**
243
+ * Returns the stored model, without resolving its referential metadata
244
+ */
245
+ rawModel?: boolean;
174
246
  from?: number;
175
247
  size?: number;
176
248
  scrollTTL?: string;
@@ -180,6 +252,10 @@ export type ApiModelSearchDevicesResult = SearchResult<KHit<DeviceModelContent>>
180
252
  export interface ApiModelSearchGroupsRequest extends ModelsControllerRequest {
181
253
  action: "searchGroups";
182
254
  tenantClasses: string[];
255
+ /**
256
+ * Returns the stored model, without resolving its referential metadata
257
+ */
258
+ rawModel?: boolean;
183
259
  from?: number;
184
260
  size?: number;
185
261
  scrollTTL?: string;
@@ -195,4 +271,19 @@ export interface ApiModelSearchMeasuresRequest extends ModelsControllerRequest {
195
271
  body?: JSONObject;
196
272
  }
197
273
  export type ApiModelSearchMeasuresResult = SearchResult<KHit<MeasureModelContent>>;
274
+ export interface ApiModelGetMetadataReferentialRequest extends ModelsControllerRequest {
275
+ action: "getMetadataReferential";
276
+ }
277
+ export type ApiModelGetMetadataReferentialResult = MetadataReferential;
278
+ export interface ApiModelWriteMetadataRequest extends ModelsControllerRequest {
279
+ action: "writeMetadata";
280
+ name: string;
281
+ body: MetadataReferentialEntry;
282
+ }
283
+ export type ApiModelWriteMetadataResult = MetadataReferential;
284
+ export interface ApiModelDeleteMetadataRequest extends ModelsControllerRequest {
285
+ action: "deleteMetadata";
286
+ name: string;
287
+ }
288
+ export type ApiModelDeleteMetadataResult = MetadataReferential;
198
289
  export {};
@@ -22,7 +22,20 @@ export interface MetadataObject {
22
22
  [key: string]: MetadataProperty | MetadataObject;
23
23
  };
24
24
  }
25
+ /**
26
+ * Marks, in the metadataMappings of a model, a metadata defined in the metadata referential.
27
+ * Its mappings are the referential ones, they are already merged into the engines collections.
28
+ */
29
+ export interface ReferentialMetadataMapping {
30
+ referential: true;
31
+ }
25
32
  export interface MetadataMappings {
33
+ [key: string]: MetadataProperty | MetadataObject | ReferentialMetadataMapping;
34
+ }
35
+ /**
36
+ * Metadata mappings without referential markers, as merged into the engines collections
37
+ */
38
+ export interface ResolvedMetadataMappings {
26
39
  [key: string]: MetadataProperty | MetadataObject;
27
40
  }
28
41
  export interface GroupAffinity {
@@ -95,9 +108,62 @@ export interface MetadataDetails {
95
108
  * Then add a new field in EditorHintEnum to define the type of your hint.
96
109
  * Finally add the new editor hint interface with a pipe to take in account the new type.
97
110
  */
98
- editorHint?: BaseEditorHint | OptionsSelectorEditorHint | DatetimeEditorHint;
111
+ editorHint?: EditorHint;
112
+ /**
113
+ * Icon representing the metadata.
114
+ * Free-form string, e.g. a FontAwesome icon name, a URL to a PNG/SVG image, or inline SVG markup.
115
+ */
116
+ icon?: string;
99
117
  };
100
118
  }
119
+ export type EditorHint = BaseEditorHint | OptionsSelectorEditorHint | DatetimeEditorHint;
120
+ /**
121
+ * A metadata defined once in the application metadata referential.
122
+ * Its mappings are merged into the engines collections when it is written,
123
+ * models use it with `{ referential: true }` in their metadataMappings.
124
+ */
125
+ export interface MetadataReferentialEntry {
126
+ /**
127
+ * Mappings of the metadata.
128
+ * They cannot be modified once written, as they are merged into the engines collections.
129
+ *
130
+ * @example
131
+ * { type: "keyword" }
132
+ * { properties: { name: { type: "keyword" } } }
133
+ */
134
+ mappings: MetadataProperty | MetadataObject;
135
+ /**
136
+ * Default translations of the metadata, copied into the metadataDetails of a model using it
137
+ */
138
+ locales: {
139
+ [locale: string]: LocaleDetails;
140
+ };
141
+ /**
142
+ * Default editor hint of the metadata
143
+ */
144
+ editorHint?: EditorHint;
145
+ /**
146
+ * Default value of the metadata
147
+ */
148
+ defaultValue?: unknown;
149
+ /**
150
+ * Default icon of the metadata.
151
+ * Free-form string, e.g. a FontAwesome icon name, a URL to a PNG/SVG image, or inline SVG markup.
152
+ */
153
+ icon?: string;
154
+ /**
155
+ * Set by the plugin: true for a metadata registered from code.
156
+ * It is written at every startup and cannot be modified or deleted through the API.
157
+ */
158
+ managed?: boolean;
159
+ }
160
+ export interface MetadataReferential {
161
+ [name: string]: MetadataReferentialEntry;
162
+ }
163
+ export interface MetadataReferentialContent extends KDocumentContent {
164
+ type: "metadata-referential";
165
+ metadata: MetadataReferential;
166
+ }
101
167
  export interface MetadataGroupLocale {
102
168
  groupFriendlyName: string;
103
169
  description: string;
@@ -118,7 +118,8 @@ export type AssetModelDefinition = {
118
118
  */
119
119
  icon?: string;
120
120
  /**
121
- * Metadata mappings definition
121
+ * Metadata mappings definition.
122
+ * Use `{ referential: true }` for a metadata of the metadata referential.
122
123
  */
123
124
  metadataMappings?: MetadataMappings;
124
125
  /**
@@ -201,7 +202,8 @@ export type DeviceModelDefinition = {
201
202
  */
202
203
  icon?: string;
203
204
  /**
204
- * Metadata mappings definition
205
+ * Metadata mappings definition.
206
+ * Use `{ referential: true }` for a metadata of the metadata referential.
205
207
  */
206
208
  metadataMappings?: MetadataMappings;
207
209
  /**
@@ -296,7 +298,8 @@ export type GroupModelDefinition = {
296
298
  */
297
299
  icon?: string;
298
300
  /**
299
- * Metadata mappings definition
301
+ * Metadata mappings definition.
302
+ * Use `{ referential: true }` for a metadata of the metadata referential.
300
303
  */
301
304
  metadataMappings?: MetadataMappings;
302
305
  /**
@@ -1,4 +1,4 @@
1
- import { AssetModelContent, DeviceModelContent, GroupModelContent, MeasureModelContent } from "./ModelContent";
1
+ import { AssetModelContent, DeviceModelContent, GroupModelContent, MeasureModelContent, MetadataReferential } from "./ModelContent";
2
2
  export type AskModelAssetGet = {
3
3
  name: "ask:device-manager:model:asset:get";
4
4
  payload: {
@@ -30,3 +30,8 @@ export type AskModelGroupGet = {
30
30
  };
31
31
  result: GroupModelContent;
32
32
  };
33
+ export type AskModelMetadataReferentialGet = {
34
+ name: "ask:device-manager:model:metadata-referential:get";
35
+ payload: void;
36
+ result: MetadataReferential;
37
+ };
@@ -5,6 +5,7 @@ import { DeviceManagerPlugin } from "./DeviceManagerPlugin";
5
5
  import { DeviceManagerConfiguration } from "./types/DeviceManagerConfiguration";
6
6
  import { InternalCollection } from "./types/InternalCollection";
7
7
  import { ConflictChunk } from "../model/ModelsConflicts";
8
+ import { MetadataMappings } from "../model/types/ModelContent";
8
9
  export type TwinType = "asset" | "device";
9
10
  export type TwinModelContent = AssetModelContent | DeviceModelContent;
10
11
  export interface EngineDocument extends KDocumentContent {
@@ -39,10 +40,42 @@ export type AskEngineUpdateConflict = {
39
40
  };
40
41
  result: ConflictChunk[];
41
42
  };
43
+ /**
44
+ * Checks a metadata of the metadata referential against the actual metadata mappings
45
+ * of the assets, devices and groups collections of every engine
46
+ */
47
+ export type AskEngineMetadataConflict = {
48
+ name: "ask:device-manager:engine:doesMetadataConflict";
49
+ payload: {
50
+ metadataMappings: MetadataMappings;
51
+ };
52
+ result: ConflictChunk[];
53
+ };
42
54
  export declare class DeviceManagerEngine extends AbstractEngine<DeviceManagerPlugin> {
43
55
  config: DeviceManagerConfiguration;
44
56
  get app(): Backend;
45
57
  constructor(plugin: Plugin, platformConfigManager: ConfigManager, engineConfigManager: ConfigManager);
58
+ /**
59
+ * Returns the actual metadata mappings of an engine collection
60
+ *
61
+ * @returns The mappings of the metadata properties, empty if the collection does not exist
62
+ */
63
+ private getCollectionMetadataMappings;
64
+ /**
65
+ * Return conflicts between the metadata mappings of models and the actual mappings
66
+ * of their collection in an engine
67
+ *
68
+ * @param engineIndex The target engine
69
+ * @param modelType The models type
70
+ * @param models The new or updated models, with their referential metadata resolved
71
+ * @returns An array of ConflictChunk
72
+ */
73
+ private getModelsMetadataConflicts;
74
+ /**
75
+ * Merges the mappings of the metadata referential and of models into metadata mappings.
76
+ * Every referential metadata is merged, used by a model or not.
77
+ */
78
+ private mergeMetadataMappings;
46
79
  /**
47
80
  * Return conflicts between the new and already present twin models
48
81
  *
@@ -2,7 +2,7 @@ import { Plugin, PluginContext } from "kuzzle";
2
2
  import { JSONObject } from "kuzzle-sdk";
3
3
  import { MeasureDefinition } from "../measure";
4
4
  import { DecoderModule, DecodersRegister } from "../decoder";
5
- import { AssetModelDefinition, DeviceModelDefinition, GroupModelDefinition, ModelsRegister } from "../model";
5
+ import { AssetModelDefinition, DeviceModelDefinition, GroupModelDefinition, MetadataReferentialEntry, ModelsRegister } from "../model";
6
6
  import { DeviceManagerConfiguration } from "./types/DeviceManagerConfiguration";
7
7
  export declare class DeviceManagerPlugin extends Plugin {
8
8
  config: DeviceManagerConfiguration;
@@ -249,6 +249,41 @@ export declare class DeviceManagerPlugin extends Plugin {
249
249
  * ```
250
250
  */
251
251
  registerMeasure: (name: string, measureDefinition: MeasureDefinition) => void;
252
+ /**
253
+ * Register a metadata in the metadata referential.
254
+ *
255
+ * Its mappings are merged into the assets, devices and groups collections of every engine,
256
+ * and cannot be modified afterwards.
257
+ * Asset, device and group models then use it with `{ referential: true }` in their
258
+ * metadataMappings instead of redefining its mappings.
259
+ * A model defining inline a metadata that conflicts with the referential is rejected.
260
+ *
261
+ * @param name Name of the metadata
262
+ * @param definition Mappings, default translations, editor hint, default value and icon
263
+ *
264
+ * @example
265
+ * ```
266
+ * deviceManager.models.registerMetadata("color", {
267
+ * mappings: { type: "keyword" },
268
+ * locales: {
269
+ * en: { friendlyName: "Color", description: "Color of the asset" },
270
+ * fr: { friendlyName: "Couleur", description: "Couleur de l'asset" },
271
+ * },
272
+ * editorHint: {
273
+ * type: EditorHintEnum.OPTION_SELECTOR,
274
+ * values: ["red", "blue"],
275
+ * },
276
+ * defaultValue: "red",
277
+ * icon: "palette",
278
+ * });
279
+ *
280
+ * deviceManager.models.registerAsset("commons", "Container", {
281
+ * measures: [],
282
+ * metadataMappings: { color: { referential: true } },
283
+ * });
284
+ * ```
285
+ */
286
+ registerMetadata: (name: string, definition: MetadataReferentialEntry) => void;
252
287
  };
253
288
  constructor();
254
289
  /**
@@ -15,6 +15,17 @@ export type DeviceManagerConfiguration = {
15
15
  */
16
16
  autoUpdate: true;
17
17
  };
18
+ models: {
19
+ metadata: {
20
+ /**
21
+ * Only accept new metadata referenced from the metadata referential in the models written through the API.
22
+ *
23
+ * New inline metadataMappings keys are rejected, the inline metadata already defined
24
+ * by a model are kept (legacy). Models registered from code are not affected.
25
+ */
26
+ referentialOnly: boolean;
27
+ };
28
+ };
18
29
  /**
19
30
  * Platform index name
20
31
  */
@@ -1 +1,7 @@
1
- export declare function lock<TReturn>(lockId: string, cb: () => Promise<TReturn>): Promise<TReturn>;
1
+ export declare function lock<TReturn>(lockId: string, cb: () => Promise<TReturn>, { ttl, }?: {
2
+ /**
3
+ * Lock TTL in milliseconds, the lock is released after it even if cb is still running
4
+ * (Kuzzle default: 5000)
5
+ */
6
+ ttl?: number;
7
+ }): Promise<TReturn>;
@@ -0,0 +1,5 @@
1
+ import { AssetModel } from "../../../index";
2
+ /**
3
+ * Asset model using the metadata referential
4
+ */
5
+ export declare const Pole: AssetModel;
@@ -3,3 +3,4 @@ export * from "./MagicHouse";
3
3
  export * from "./Room";
4
4
  export * from "./StreetLamp";
5
5
  export * from "./Warehouse";
6
+ export * from "./Pole";
@@ -0,0 +1,5 @@
1
+ import { MetadataReferentialEntry } from "../../index";
2
+ export declare const metadataReferential: Array<{
3
+ name: string;
4
+ definition: MetadataReferentialEntry;
5
+ }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kuzzle-device-manager-types",
3
- "version": "3.0.0-3-dev.20",
3
+ "version": "3.0.0-3-dev.21",
4
4
  "description": "Shared types for Kuzzle Device Manager",
5
5
  "author": "The Kuzzle Team (support@kuzzle.io)",
6
6
  "main": "index.js",