@twin.org/entity-storage-connector-cosmosdb 0.0.2-next.1 → 0.0.2-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ The tests developed are functional tests and need an instance of CosmosDB up and
15
15
  To run a Docker image of Azure CosmosDB:
16
16
 
17
17
  ```sh
18
- docker run -d --platform=linux/amd64 -p 8081:8081 -p 10250:10250 -p 10251:10251 -p 10252:10252 -p 10253:10253 -p 10254:10254 -m 3g --name twin-entity-storage-cosmos -e AZURE_COSMOS_EMULATOR_PARTITION_COUNT=10 -e AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true -e AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE='127.0.0.1' mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
18
+ docker run -d --platform=linux/amd64 -p 8081:8081 -m 3g --name twin-entity-storage-cosmos -e AZURE_COSMOS_EMULATOR_PARTITION_COUNT=10 -e AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true -e AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE='127.0.0.1' mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
19
19
  ```
20
20
 
21
21
  Or
@@ -3,7 +3,6 @@
3
3
  var cosmos = require('@azure/cosmos');
4
4
  var core = require('@twin.org/core');
5
5
  var entity = require('@twin.org/entity');
6
- var loggingModels = require('@twin.org/logging-models');
7
6
 
8
7
  // Copyright 2024 IOTA Stiftung.
9
8
  // SPDX-License-Identifier: Apache-2.0.
@@ -11,11 +10,15 @@ var loggingModels = require('@twin.org/logging-models');
11
10
  * Class for performing entity storage operations using Cosmos DB.
12
11
  */
13
12
  class CosmosDbEntityStorageConnector {
13
+ /**
14
+ * Runtime name for the class.
15
+ */
16
+ static CLASS_NAME = "CosmosDbEntityStorageConnector";
14
17
  /**
15
18
  * Limit the number of entities when finding.
16
19
  * @internal
17
20
  */
18
- static _PAGE_SIZE = 40;
21
+ static _DEFAULT_LIMIT = 40;
19
22
  /**
20
23
  * Partition id field name.
21
24
  * @internal
@@ -31,10 +34,6 @@ class CosmosDbEntityStorageConnector {
31
34
  * @internal
32
35
  */
33
36
  static _PARTITION_ID_VALUE = "1";
34
- /**
35
- * Runtime name for the class.
36
- */
37
- CLASS_NAME = "CosmosDbEntityStorageConnector";
38
37
  /**
39
38
  * The schema for the entity.
40
39
  * @internal
@@ -65,13 +64,13 @@ class CosmosDbEntityStorageConnector {
65
64
  * @param options The options for the connector.
66
65
  */
67
66
  constructor(options) {
68
- core.Guards.object(this.CLASS_NAME, "options", options);
69
- core.Guards.stringValue(this.CLASS_NAME, "options.entitySchema", options.entitySchema);
70
- core.Guards.object(this.CLASS_NAME, "options.config", options.config);
71
- core.Guards.stringValue(this.CLASS_NAME, "options.config.endpoint", options.config.endpoint);
72
- core.Guards.stringValue(this.CLASS_NAME, "options.config.key", options.config.key);
73
- core.Guards.stringValue(this.CLASS_NAME, "options.config.databaseId", options.config.databaseId);
74
- core.Guards.stringValue(this.CLASS_NAME, "options.config.containerId", options.config.containerId);
67
+ core.Guards.object(CosmosDbEntityStorageConnector.CLASS_NAME, "options", options);
68
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.entitySchema", options.entitySchema);
69
+ core.Guards.object(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config", options.config);
70
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.endpoint", options.config.endpoint);
71
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.key", options.config.key);
72
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.databaseId", options.config.databaseId);
73
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.containerId", options.config.containerId);
75
74
  this._entitySchema = entity.EntitySchemaFactory.get(options.entitySchema);
76
75
  this._primaryKey = entity.EntitySchemaHelper.getPrimaryKey(this._entitySchema);
77
76
  this._config = options.config;
@@ -86,16 +85,16 @@ class CosmosDbEntityStorageConnector {
86
85
  }
87
86
  /**
88
87
  * Initialize the Cosmos DB environment.
89
- * @param nodeLoggingConnectorType Optional type of the logging connector.
88
+ * @param nodeLoggingComponentType Optional type of the logging component.
90
89
  * @returns A promise that resolves to a boolean indicating success.
91
90
  */
92
- async bootstrap(nodeLoggingConnectorType) {
93
- const nodeLogging = loggingModels.LoggingConnectorFactory.getIfExists(nodeLoggingConnectorType ?? "node-logging");
91
+ async bootstrap(nodeLoggingComponentType) {
92
+ const nodeLogging = core.ComponentFactory.getIfExists(nodeLoggingComponentType);
94
93
  // Create the database if it does not exist
95
94
  try {
96
95
  await nodeLogging?.log({
97
96
  level: "info",
98
- source: this.CLASS_NAME,
97
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
99
98
  ts: Date.now(),
100
99
  message: "databaseCreating",
101
100
  data: {
@@ -105,10 +104,10 @@ class CosmosDbEntityStorageConnector {
105
104
  const { resource: databaseDefinition } = await this._client.databases.createIfNotExists({
106
105
  id: this._config.databaseId
107
106
  });
108
- core.Guards.stringValue(this.CLASS_NAME, "databaseDefinition.id", databaseDefinition?.id);
107
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "databaseDefinition.id", databaseDefinition?.id);
109
108
  await nodeLogging?.log({
110
109
  level: "info",
111
- source: this.CLASS_NAME,
110
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
112
111
  ts: Date.now(),
113
112
  message: "databaseExists",
114
113
  data: {
@@ -120,28 +119,25 @@ class CosmosDbEntityStorageConnector {
120
119
  if (core.BaseError.isErrorCode(error, "Conflict")) {
121
120
  await nodeLogging?.log({
122
121
  level: "info",
123
- source: this.CLASS_NAME,
122
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
124
123
  ts: Date.now(),
125
- message: "databaseAlreadyExists",
124
+ message: "databaseExists",
126
125
  data: {
127
126
  databaseId: this._config.databaseId
128
127
  }
129
128
  });
130
129
  }
131
130
  else {
132
- const errors = error instanceof AggregateError ? error.errors : [error];
133
- for (const err of errors) {
134
- await nodeLogging?.log({
135
- level: "error",
136
- source: this.CLASS_NAME,
137
- ts: Date.now(),
138
- message: "databaseCreateFailed",
139
- error: core.BaseError.fromError(err),
140
- data: {
141
- databaseId: this._config.databaseId
142
- }
143
- });
144
- }
131
+ await nodeLogging?.log({
132
+ level: "error",
133
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
134
+ ts: Date.now(),
135
+ message: "databaseCreateFailed",
136
+ error: core.BaseError.fromError(error),
137
+ data: {
138
+ databaseId: this._config.databaseId
139
+ }
140
+ });
145
141
  return false;
146
142
  }
147
143
  }
@@ -159,7 +155,7 @@ class CosmosDbEntityStorageConnector {
159
155
  if (containerDefinition) {
160
156
  await nodeLogging?.log({
161
157
  level: "info",
162
- source: this.CLASS_NAME,
158
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
163
159
  ts: Date.now(),
164
160
  message: "containerExists",
165
161
  data: {
@@ -170,7 +166,7 @@ class CosmosDbEntityStorageConnector {
170
166
  else {
171
167
  await nodeLogging?.log({
172
168
  level: "error",
173
- source: this.CLASS_NAME,
169
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
174
170
  ts: Date.now(),
175
171
  message: "containerNotExisting",
176
172
  data: {
@@ -183,7 +179,7 @@ class CosmosDbEntityStorageConnector {
183
179
  catch (error) {
184
180
  await nodeLogging?.log({
185
181
  level: "error",
186
- source: this.CLASS_NAME,
182
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
187
183
  ts: Date.now(),
188
184
  message: "containerCreateFailed",
189
185
  error: core.BaseError.fromError(error),
@@ -210,7 +206,7 @@ class CosmosDbEntityStorageConnector {
210
206
  * @returns The object if it can be found or undefined.
211
207
  */
212
208
  async get(id, secondaryIndex, conditions) {
213
- core.Guards.stringValue(this.CLASS_NAME, "id", id);
209
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "id", id);
214
210
  try {
215
211
  // No secondary index or conditions
216
212
  if (core.Is.empty(secondaryIndex) && !core.Is.arrayValue(conditions)) {
@@ -234,7 +230,9 @@ class CosmosDbEntityStorageConnector {
234
230
  if (core.Is.arrayValue(conditions)) {
235
231
  for (const c of conditions) {
236
232
  const schemaProp = this._entitySchema.properties?.find(p => p.property === c.property);
237
- whereQuery.push(`c.${String(c.property)} = ${this.propertyToDbValue(c.value, schemaProp?.type)}`);
233
+ whereQuery.push(
234
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
235
+ `c.${String(c.property)} = ${this.propertyToDbValue(c.value, schemaProp?.type)}`);
238
236
  }
239
237
  }
240
238
  const query = {
@@ -251,11 +249,11 @@ class CosmosDbEntityStorageConnector {
251
249
  }
252
250
  catch (err) {
253
251
  if (core.BaseError.isErrorCode(err, "NotFound")) {
254
- throw new core.GeneralError(this.CLASS_NAME, "containerDoesNotExist", {
255
- container: this._config.containerId
252
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "containerDoesNotExist", {
253
+ containerId: this._config.containerId
256
254
  }, err);
257
255
  }
258
- throw new core.GeneralError(this.CLASS_NAME, "getFailed", {
256
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "getFailed", {
259
257
  id
260
258
  }, err);
261
259
  }
@@ -268,7 +266,7 @@ class CosmosDbEntityStorageConnector {
268
266
  * @returns The id of the entity.
269
267
  */
270
268
  async set(entity$1, conditions) {
271
- core.Guards.object(this.CLASS_NAME, "entity", entity$1);
269
+ core.Guards.object(CosmosDbEntityStorageConnector.CLASS_NAME, "entity", entity$1);
272
270
  entity.EntitySchemaHelper.validateEntity(entity$1, this.getSchema());
273
271
  const id = entity$1[this._primaryKey.property];
274
272
  try {
@@ -286,12 +284,15 @@ class CosmosDbEntityStorageConnector {
286
284
  });
287
285
  }
288
286
  catch (err) {
289
- if (core.BaseError.isErrorCode(err, "ResourceNotFoundException")) {
290
- throw new core.GeneralError(this.CLASS_NAME, "containerDoesNotExist", {
291
- containerId: this._config.containerId
292
- }, err);
287
+ if (core.BaseError.isAggregateError(err)) {
288
+ const errors = core.BaseError.fromAggregate(err);
289
+ if (core.BaseError.someErrorCode(errors, "ResourceNotFoundException")) {
290
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "containerDoesNotExist", {
291
+ containerId: this._config.containerId
292
+ }, err);
293
+ }
293
294
  }
294
- throw new core.GeneralError(this.CLASS_NAME, "setFailed", {
295
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "setFailed", {
295
296
  id
296
297
  }, err);
297
298
  }
@@ -303,7 +304,7 @@ class CosmosDbEntityStorageConnector {
303
304
  * @returns Nothing.
304
305
  */
305
306
  async remove(id, conditions) {
306
- core.Guards.stringValue(this.CLASS_NAME, "id", id);
307
+ core.Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "id", id);
307
308
  try {
308
309
  const item = await this._container.item(id, CosmosDbEntityStorageConnector._PARTITION_ID_VALUE);
309
310
  const { resource: itemData } = await item.read();
@@ -320,7 +321,7 @@ class CosmosDbEntityStorageConnector {
320
321
  err.body?.code === "NotFound") {
321
322
  return;
322
323
  }
323
- throw new core.GeneralError(this.CLASS_NAME, "removeFailed", {
324
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "removeFailed", {
324
325
  id
325
326
  }, err);
326
327
  }
@@ -330,19 +331,19 @@ class CosmosDbEntityStorageConnector {
330
331
  * @param conditions The conditions to match for the entities.
331
332
  * @param sortProperties The optional sort order.
332
333
  * @param properties The optional properties to return, defaults to all.
333
- * @param cursor The cursor to request the next page of entities.
334
- * @param pageSize The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
334
+ * @param cursor The cursor to request the next chunk of entities.
335
+ * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
335
336
  * @returns All the entities for the storage matching the conditions,
336
337
  * and a cursor which can be used to request more entities.
337
338
  */
338
- async query(conditions, sortProperties, properties, cursor, pageSize) {
339
+ async query(conditions, sortProperties, properties, cursor, limit) {
339
340
  const sql = "";
340
341
  try {
341
- const returnSize = pageSize ?? CosmosDbEntityStorageConnector._PAGE_SIZE;
342
+ const returnSize = limit ?? CosmosDbEntityStorageConnector._DEFAULT_LIMIT;
342
343
  let orderByClause = "";
343
344
  if (Array.isArray(sortProperties)) {
344
345
  if (sortProperties.length > 1) {
345
- throw new core.GeneralError(this.CLASS_NAME, "sortSingle");
346
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "sortSingle");
346
347
  }
347
348
  for (const sortProperty of sortProperties) {
348
349
  const propertySchema = this._entitySchema.properties?.find(e => e.property === sortProperty.property);
@@ -350,7 +351,7 @@ class CosmosDbEntityStorageConnector {
350
351
  (!propertySchema.isPrimary &&
351
352
  !propertySchema.isSecondary &&
352
353
  !propertySchema.sortDirection)) {
353
- throw new core.GeneralError(this.CLASS_NAME, "sortNotIndexed", {
354
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "sortNotIndexed", {
354
355
  property: sortProperty.property
355
356
  });
356
357
  }
@@ -382,7 +383,7 @@ class CosmosDbEntityStorageConnector {
382
383
  };
383
384
  }
384
385
  catch (err) {
385
- throw new core.GeneralError(this.CLASS_NAME, "queryFailed", { sql }, err);
386
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "queryFailed", { sql }, err);
386
387
  }
387
388
  }
388
389
  /**
@@ -501,7 +502,7 @@ class CosmosDbEntityStorageConnector {
501
502
  else if (comparator.comparison === entity.ComparisonOperator.In) {
502
503
  return `c.${propName} IN ${attributeName}`;
503
504
  }
504
- throw new core.GeneralError(this.CLASS_NAME, "comparisonNotSupported", {
505
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "comparisonNotSupported", {
505
506
  comparison: comparator.comparison
506
507
  });
507
508
  }
@@ -564,7 +565,9 @@ class CosmosDbEntityStorageConnector {
564
565
  else if (operator === entity.LogicalOperator.Or) {
565
566
  return "OR";
566
567
  }
567
- throw new core.GeneralError(this.CLASS_NAME, "conditionalNotSupported", { operator });
568
+ throw new core.GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "conditionalNotSupported", {
569
+ operator
570
+ });
568
571
  }
569
572
  /**
570
573
  * Verify the conditions for the entity.
@@ -1,7 +1,6 @@
1
1
  import { CosmosClient, CosmosDbDiagnosticLevel, PartitionKeyKind } from '@azure/cosmos';
2
- import { Guards, BaseError, Is, GeneralError, Coerce, ObjectHelper } from '@twin.org/core';
2
+ import { Guards, ComponentFactory, BaseError, Is, GeneralError, Coerce, ObjectHelper } from '@twin.org/core';
3
3
  import { EntitySchemaFactory, EntitySchemaHelper, SortDirection, ComparisonOperator, LogicalOperator } from '@twin.org/entity';
4
- import { LoggingConnectorFactory } from '@twin.org/logging-models';
5
4
 
6
5
  // Copyright 2024 IOTA Stiftung.
7
6
  // SPDX-License-Identifier: Apache-2.0.
@@ -9,11 +8,15 @@ import { LoggingConnectorFactory } from '@twin.org/logging-models';
9
8
  * Class for performing entity storage operations using Cosmos DB.
10
9
  */
11
10
  class CosmosDbEntityStorageConnector {
11
+ /**
12
+ * Runtime name for the class.
13
+ */
14
+ static CLASS_NAME = "CosmosDbEntityStorageConnector";
12
15
  /**
13
16
  * Limit the number of entities when finding.
14
17
  * @internal
15
18
  */
16
- static _PAGE_SIZE = 40;
19
+ static _DEFAULT_LIMIT = 40;
17
20
  /**
18
21
  * Partition id field name.
19
22
  * @internal
@@ -29,10 +32,6 @@ class CosmosDbEntityStorageConnector {
29
32
  * @internal
30
33
  */
31
34
  static _PARTITION_ID_VALUE = "1";
32
- /**
33
- * Runtime name for the class.
34
- */
35
- CLASS_NAME = "CosmosDbEntityStorageConnector";
36
35
  /**
37
36
  * The schema for the entity.
38
37
  * @internal
@@ -63,13 +62,13 @@ class CosmosDbEntityStorageConnector {
63
62
  * @param options The options for the connector.
64
63
  */
65
64
  constructor(options) {
66
- Guards.object(this.CLASS_NAME, "options", options);
67
- Guards.stringValue(this.CLASS_NAME, "options.entitySchema", options.entitySchema);
68
- Guards.object(this.CLASS_NAME, "options.config", options.config);
69
- Guards.stringValue(this.CLASS_NAME, "options.config.endpoint", options.config.endpoint);
70
- Guards.stringValue(this.CLASS_NAME, "options.config.key", options.config.key);
71
- Guards.stringValue(this.CLASS_NAME, "options.config.databaseId", options.config.databaseId);
72
- Guards.stringValue(this.CLASS_NAME, "options.config.containerId", options.config.containerId);
65
+ Guards.object(CosmosDbEntityStorageConnector.CLASS_NAME, "options", options);
66
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.entitySchema", options.entitySchema);
67
+ Guards.object(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config", options.config);
68
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.endpoint", options.config.endpoint);
69
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.key", options.config.key);
70
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.databaseId", options.config.databaseId);
71
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "options.config.containerId", options.config.containerId);
73
72
  this._entitySchema = EntitySchemaFactory.get(options.entitySchema);
74
73
  this._primaryKey = EntitySchemaHelper.getPrimaryKey(this._entitySchema);
75
74
  this._config = options.config;
@@ -84,16 +83,16 @@ class CosmosDbEntityStorageConnector {
84
83
  }
85
84
  /**
86
85
  * Initialize the Cosmos DB environment.
87
- * @param nodeLoggingConnectorType Optional type of the logging connector.
86
+ * @param nodeLoggingComponentType Optional type of the logging component.
88
87
  * @returns A promise that resolves to a boolean indicating success.
89
88
  */
90
- async bootstrap(nodeLoggingConnectorType) {
91
- const nodeLogging = LoggingConnectorFactory.getIfExists(nodeLoggingConnectorType ?? "node-logging");
89
+ async bootstrap(nodeLoggingComponentType) {
90
+ const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
92
91
  // Create the database if it does not exist
93
92
  try {
94
93
  await nodeLogging?.log({
95
94
  level: "info",
96
- source: this.CLASS_NAME,
95
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
97
96
  ts: Date.now(),
98
97
  message: "databaseCreating",
99
98
  data: {
@@ -103,10 +102,10 @@ class CosmosDbEntityStorageConnector {
103
102
  const { resource: databaseDefinition } = await this._client.databases.createIfNotExists({
104
103
  id: this._config.databaseId
105
104
  });
106
- Guards.stringValue(this.CLASS_NAME, "databaseDefinition.id", databaseDefinition?.id);
105
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "databaseDefinition.id", databaseDefinition?.id);
107
106
  await nodeLogging?.log({
108
107
  level: "info",
109
- source: this.CLASS_NAME,
108
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
110
109
  ts: Date.now(),
111
110
  message: "databaseExists",
112
111
  data: {
@@ -118,28 +117,25 @@ class CosmosDbEntityStorageConnector {
118
117
  if (BaseError.isErrorCode(error, "Conflict")) {
119
118
  await nodeLogging?.log({
120
119
  level: "info",
121
- source: this.CLASS_NAME,
120
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
122
121
  ts: Date.now(),
123
- message: "databaseAlreadyExists",
122
+ message: "databaseExists",
124
123
  data: {
125
124
  databaseId: this._config.databaseId
126
125
  }
127
126
  });
128
127
  }
129
128
  else {
130
- const errors = error instanceof AggregateError ? error.errors : [error];
131
- for (const err of errors) {
132
- await nodeLogging?.log({
133
- level: "error",
134
- source: this.CLASS_NAME,
135
- ts: Date.now(),
136
- message: "databaseCreateFailed",
137
- error: BaseError.fromError(err),
138
- data: {
139
- databaseId: this._config.databaseId
140
- }
141
- });
142
- }
129
+ await nodeLogging?.log({
130
+ level: "error",
131
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
132
+ ts: Date.now(),
133
+ message: "databaseCreateFailed",
134
+ error: BaseError.fromError(error),
135
+ data: {
136
+ databaseId: this._config.databaseId
137
+ }
138
+ });
143
139
  return false;
144
140
  }
145
141
  }
@@ -157,7 +153,7 @@ class CosmosDbEntityStorageConnector {
157
153
  if (containerDefinition) {
158
154
  await nodeLogging?.log({
159
155
  level: "info",
160
- source: this.CLASS_NAME,
156
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
161
157
  ts: Date.now(),
162
158
  message: "containerExists",
163
159
  data: {
@@ -168,7 +164,7 @@ class CosmosDbEntityStorageConnector {
168
164
  else {
169
165
  await nodeLogging?.log({
170
166
  level: "error",
171
- source: this.CLASS_NAME,
167
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
172
168
  ts: Date.now(),
173
169
  message: "containerNotExisting",
174
170
  data: {
@@ -181,7 +177,7 @@ class CosmosDbEntityStorageConnector {
181
177
  catch (error) {
182
178
  await nodeLogging?.log({
183
179
  level: "error",
184
- source: this.CLASS_NAME,
180
+ source: CosmosDbEntityStorageConnector.CLASS_NAME,
185
181
  ts: Date.now(),
186
182
  message: "containerCreateFailed",
187
183
  error: BaseError.fromError(error),
@@ -208,7 +204,7 @@ class CosmosDbEntityStorageConnector {
208
204
  * @returns The object if it can be found or undefined.
209
205
  */
210
206
  async get(id, secondaryIndex, conditions) {
211
- Guards.stringValue(this.CLASS_NAME, "id", id);
207
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "id", id);
212
208
  try {
213
209
  // No secondary index or conditions
214
210
  if (Is.empty(secondaryIndex) && !Is.arrayValue(conditions)) {
@@ -232,7 +228,9 @@ class CosmosDbEntityStorageConnector {
232
228
  if (Is.arrayValue(conditions)) {
233
229
  for (const c of conditions) {
234
230
  const schemaProp = this._entitySchema.properties?.find(p => p.property === c.property);
235
- whereQuery.push(`c.${String(c.property)} = ${this.propertyToDbValue(c.value, schemaProp?.type)}`);
231
+ whereQuery.push(
232
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
233
+ `c.${String(c.property)} = ${this.propertyToDbValue(c.value, schemaProp?.type)}`);
236
234
  }
237
235
  }
238
236
  const query = {
@@ -249,11 +247,11 @@ class CosmosDbEntityStorageConnector {
249
247
  }
250
248
  catch (err) {
251
249
  if (BaseError.isErrorCode(err, "NotFound")) {
252
- throw new GeneralError(this.CLASS_NAME, "containerDoesNotExist", {
253
- container: this._config.containerId
250
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "containerDoesNotExist", {
251
+ containerId: this._config.containerId
254
252
  }, err);
255
253
  }
256
- throw new GeneralError(this.CLASS_NAME, "getFailed", {
254
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "getFailed", {
257
255
  id
258
256
  }, err);
259
257
  }
@@ -266,7 +264,7 @@ class CosmosDbEntityStorageConnector {
266
264
  * @returns The id of the entity.
267
265
  */
268
266
  async set(entity, conditions) {
269
- Guards.object(this.CLASS_NAME, "entity", entity);
267
+ Guards.object(CosmosDbEntityStorageConnector.CLASS_NAME, "entity", entity);
270
268
  EntitySchemaHelper.validateEntity(entity, this.getSchema());
271
269
  const id = entity[this._primaryKey.property];
272
270
  try {
@@ -284,12 +282,15 @@ class CosmosDbEntityStorageConnector {
284
282
  });
285
283
  }
286
284
  catch (err) {
287
- if (BaseError.isErrorCode(err, "ResourceNotFoundException")) {
288
- throw new GeneralError(this.CLASS_NAME, "containerDoesNotExist", {
289
- containerId: this._config.containerId
290
- }, err);
285
+ if (BaseError.isAggregateError(err)) {
286
+ const errors = BaseError.fromAggregate(err);
287
+ if (BaseError.someErrorCode(errors, "ResourceNotFoundException")) {
288
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "containerDoesNotExist", {
289
+ containerId: this._config.containerId
290
+ }, err);
291
+ }
291
292
  }
292
- throw new GeneralError(this.CLASS_NAME, "setFailed", {
293
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "setFailed", {
293
294
  id
294
295
  }, err);
295
296
  }
@@ -301,7 +302,7 @@ class CosmosDbEntityStorageConnector {
301
302
  * @returns Nothing.
302
303
  */
303
304
  async remove(id, conditions) {
304
- Guards.stringValue(this.CLASS_NAME, "id", id);
305
+ Guards.stringValue(CosmosDbEntityStorageConnector.CLASS_NAME, "id", id);
305
306
  try {
306
307
  const item = await this._container.item(id, CosmosDbEntityStorageConnector._PARTITION_ID_VALUE);
307
308
  const { resource: itemData } = await item.read();
@@ -318,7 +319,7 @@ class CosmosDbEntityStorageConnector {
318
319
  err.body?.code === "NotFound") {
319
320
  return;
320
321
  }
321
- throw new GeneralError(this.CLASS_NAME, "removeFailed", {
322
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "removeFailed", {
322
323
  id
323
324
  }, err);
324
325
  }
@@ -328,19 +329,19 @@ class CosmosDbEntityStorageConnector {
328
329
  * @param conditions The conditions to match for the entities.
329
330
  * @param sortProperties The optional sort order.
330
331
  * @param properties The optional properties to return, defaults to all.
331
- * @param cursor The cursor to request the next page of entities.
332
- * @param pageSize The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
332
+ * @param cursor The cursor to request the next chunk of entities.
333
+ * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
333
334
  * @returns All the entities for the storage matching the conditions,
334
335
  * and a cursor which can be used to request more entities.
335
336
  */
336
- async query(conditions, sortProperties, properties, cursor, pageSize) {
337
+ async query(conditions, sortProperties, properties, cursor, limit) {
337
338
  const sql = "";
338
339
  try {
339
- const returnSize = pageSize ?? CosmosDbEntityStorageConnector._PAGE_SIZE;
340
+ const returnSize = limit ?? CosmosDbEntityStorageConnector._DEFAULT_LIMIT;
340
341
  let orderByClause = "";
341
342
  if (Array.isArray(sortProperties)) {
342
343
  if (sortProperties.length > 1) {
343
- throw new GeneralError(this.CLASS_NAME, "sortSingle");
344
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "sortSingle");
344
345
  }
345
346
  for (const sortProperty of sortProperties) {
346
347
  const propertySchema = this._entitySchema.properties?.find(e => e.property === sortProperty.property);
@@ -348,7 +349,7 @@ class CosmosDbEntityStorageConnector {
348
349
  (!propertySchema.isPrimary &&
349
350
  !propertySchema.isSecondary &&
350
351
  !propertySchema.sortDirection)) {
351
- throw new GeneralError(this.CLASS_NAME, "sortNotIndexed", {
352
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "sortNotIndexed", {
352
353
  property: sortProperty.property
353
354
  });
354
355
  }
@@ -380,7 +381,7 @@ class CosmosDbEntityStorageConnector {
380
381
  };
381
382
  }
382
383
  catch (err) {
383
- throw new GeneralError(this.CLASS_NAME, "queryFailed", { sql }, err);
384
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "queryFailed", { sql }, err);
384
385
  }
385
386
  }
386
387
  /**
@@ -499,7 +500,7 @@ class CosmosDbEntityStorageConnector {
499
500
  else if (comparator.comparison === ComparisonOperator.In) {
500
501
  return `c.${propName} IN ${attributeName}`;
501
502
  }
502
- throw new GeneralError(this.CLASS_NAME, "comparisonNotSupported", {
503
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "comparisonNotSupported", {
503
504
  comparison: comparator.comparison
504
505
  });
505
506
  }
@@ -562,7 +563,9 @@ class CosmosDbEntityStorageConnector {
562
563
  else if (operator === LogicalOperator.Or) {
563
564
  return "OR";
564
565
  }
565
- throw new GeneralError(this.CLASS_NAME, "conditionalNotSupported", { operator });
566
+ throw new GeneralError(CosmosDbEntityStorageConnector.CLASS_NAME, "conditionalNotSupported", {
567
+ operator
568
+ });
566
569
  }
567
570
  /**
568
571
  * Verify the conditions for the entity.
@@ -8,7 +8,7 @@ export declare class CosmosDbEntityStorageConnector<T = unknown> implements IEnt
8
8
  /**
9
9
  * Runtime name for the class.
10
10
  */
11
- readonly CLASS_NAME: string;
11
+ static readonly CLASS_NAME: string;
12
12
  /**
13
13
  * Create a new instance of CosmosDbEntityStorageConnector.
14
14
  * @param options The options for the connector.
@@ -16,10 +16,10 @@ export declare class CosmosDbEntityStorageConnector<T = unknown> implements IEnt
16
16
  constructor(options: ICosmosDbEntityStorageConnectorConstructorOptions);
17
17
  /**
18
18
  * Initialize the Cosmos DB environment.
19
- * @param nodeLoggingConnectorType Optional type of the logging connector.
19
+ * @param nodeLoggingComponentType Optional type of the logging component.
20
20
  * @returns A promise that resolves to a boolean indicating success.
21
21
  */
22
- bootstrap(nodeLoggingConnectorType?: string): Promise<boolean>;
22
+ bootstrap(nodeLoggingComponentType?: string): Promise<boolean>;
23
23
  /**
24
24
  * Get the schema for the entities.
25
25
  * @returns The schema for the entities.
@@ -61,15 +61,15 @@ export declare class CosmosDbEntityStorageConnector<T = unknown> implements IEnt
61
61
  * @param conditions The conditions to match for the entities.
62
62
  * @param sortProperties The optional sort order.
63
63
  * @param properties The optional properties to return, defaults to all.
64
- * @param cursor The cursor to request the next page of entities.
65
- * @param pageSize The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
64
+ * @param cursor The cursor to request the next chunk of entities.
65
+ * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
66
66
  * @returns All the entities for the storage matching the conditions,
67
67
  * and a cursor which can be used to request more entities.
68
68
  */
69
69
  query(conditions?: EntityCondition<T>, sortProperties?: {
70
70
  property: keyof T;
71
71
  sortDirection: SortDirection;
72
- }[], properties?: (keyof T)[], cursor?: string, pageSize?: number): Promise<{
72
+ }[], properties?: (keyof T)[], cursor?: string, limit?: number): Promise<{
73
73
  entities: Partial<T>[];
74
74
  cursor?: string;
75
75
  }>;
@@ -8,10 +8,10 @@ export interface ICosmosDbEntityStorageConnectorConstructorOptions {
8
8
  */
9
9
  entitySchema: string;
10
10
  /**
11
- * The type of logging connector to use.
11
+ * The type of logging component to use.
12
12
  * @default logging
13
13
  */
14
- loggingConnectorType?: string;
14
+ loggingComponentType?: string;
15
15
  /**
16
16
  * The configuration for the connector.
17
17
  */
package/docs/changelog.md CHANGED
@@ -1,5 +1,149 @@
1
1
  # @twin.org/entity-storage-connector-cosmosdb - Changelog
2
2
 
3
+ ## [0.0.2-next.10](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.9...entity-storage-connector-cosmosdb-v0.0.2-next.10) (2025-10-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * add validate-locales ([e66ef0d](https://github.com/twinfoundation/entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.9 to 0.0.2-next.10
16
+ * devDependencies
17
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.9 to 0.0.2-next.10
18
+
19
+ ## [0.0.2-next.9](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.8...entity-storage-connector-cosmosdb-v0.0.2-next.9) (2025-10-02)
20
+
21
+
22
+ ### Miscellaneous Chores
23
+
24
+ * **entity-storage-connector-cosmosdb:** Synchronize repo versions
25
+
26
+
27
+ ### Dependencies
28
+
29
+ * The following workspace dependencies were updated
30
+ * dependencies
31
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.8 to 0.0.2-next.9
32
+ * devDependencies
33
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.8 to 0.0.2-next.9
34
+
35
+ ## [0.0.2-next.8](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.7...entity-storage-connector-cosmosdb-v0.0.2-next.8) (2025-08-29)
36
+
37
+
38
+ ### Features
39
+
40
+ * eslint migration to flat config ([f033b64](https://github.com/twinfoundation/entity-storage/commit/f033b64984c0e6a8129d929c9dd816dcc1b8dab0))
41
+
42
+
43
+ ### Dependencies
44
+
45
+ * The following workspace dependencies were updated
46
+ * dependencies
47
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.7 to 0.0.2-next.8
48
+ * devDependencies
49
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.7 to 0.0.2-next.8
50
+
51
+ ## [0.0.2-next.7](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.6...entity-storage-connector-cosmosdb-v0.0.2-next.7) (2025-08-20)
52
+
53
+
54
+ ### Features
55
+
56
+ * logging naming consistency ([f99d12d](https://github.com/twinfoundation/entity-storage/commit/f99d12dea04b6d4f2b5632ff5473e9ec7d5f9055))
57
+
58
+
59
+ ### Dependencies
60
+
61
+ * The following workspace dependencies were updated
62
+ * dependencies
63
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.6 to 0.0.2-next.7
64
+ * devDependencies
65
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.6 to 0.0.2-next.7
66
+
67
+ ## [0.0.2-next.6](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.5...entity-storage-connector-cosmosdb-v0.0.2-next.6) (2025-08-19)
68
+
69
+
70
+ ### Features
71
+
72
+ * update framework core ([b59a380](https://github.com/twinfoundation/entity-storage/commit/b59a380bb7fba2b43610f69074dcdee24a4737da))
73
+
74
+
75
+ ### Dependencies
76
+
77
+ * The following workspace dependencies were updated
78
+ * dependencies
79
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.5 to 0.0.2-next.6
80
+ * devDependencies
81
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.5 to 0.0.2-next.6
82
+
83
+ ## [0.0.2-next.5](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.4...entity-storage-connector-cosmosdb-v0.0.2-next.5) (2025-08-11)
84
+
85
+
86
+ ### Miscellaneous Chores
87
+
88
+ * **entity-storage-connector-cosmosdb:** Synchronize repo versions
89
+
90
+
91
+ ### Dependencies
92
+
93
+ * The following workspace dependencies were updated
94
+ * dependencies
95
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.4 to 0.0.2-next.5
96
+ * devDependencies
97
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.4 to 0.0.2-next.5
98
+
99
+ ## [0.0.2-next.4](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.3...entity-storage-connector-cosmosdb-v0.0.2-next.4) (2025-08-08)
100
+
101
+
102
+ ### Miscellaneous Chores
103
+
104
+ * **entity-storage-connector-cosmosdb:** Synchronize repo versions
105
+
106
+
107
+ ### Dependencies
108
+
109
+ * The following workspace dependencies were updated
110
+ * dependencies
111
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.3 to 0.0.2-next.4
112
+ * devDependencies
113
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.3 to 0.0.2-next.4
114
+
115
+ ## [0.0.2-next.3](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.2...entity-storage-connector-cosmosdb-v0.0.2-next.3) (2025-07-25)
116
+
117
+
118
+ ### Miscellaneous Chores
119
+
120
+ * **entity-storage-connector-cosmosdb:** Synchronize repo versions
121
+
122
+
123
+ ### Dependencies
124
+
125
+ * The following workspace dependencies were updated
126
+ * dependencies
127
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.2 to 0.0.2-next.3
128
+ * devDependencies
129
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.2 to 0.0.2-next.3
130
+
131
+ ## [0.0.2-next.2](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.1...entity-storage-connector-cosmosdb-v0.0.2-next.2) (2025-07-24)
132
+
133
+
134
+ ### Miscellaneous Chores
135
+
136
+ * **entity-storage-connector-cosmosdb:** Synchronize repo versions
137
+
138
+
139
+ ### Dependencies
140
+
141
+ * The following workspace dependencies were updated
142
+ * dependencies
143
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.1 to 0.0.2-next.2
144
+ * devDependencies
145
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.1 to 0.0.2-next.2
146
+
3
147
  ## [0.0.2-next.1](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-cosmosdb-v0.0.2-next.0...entity-storage-connector-cosmosdb-v0.0.2-next.1) (2025-07-17)
4
148
 
5
149
 
@@ -36,29 +36,25 @@ The options for the connector.
36
36
 
37
37
  ### CLASS\_NAME
38
38
 
39
- > `readonly` **CLASS\_NAME**: `string`
39
+ > `readonly` `static` **CLASS\_NAME**: `string`
40
40
 
41
41
  Runtime name for the class.
42
42
 
43
- #### Implementation of
44
-
45
- `IEntityStorageConnector.CLASS_NAME`
46
-
47
43
  ## Methods
48
44
 
49
45
  ### bootstrap()
50
46
 
51
- > **bootstrap**(`nodeLoggingConnectorType?`): `Promise`\<`boolean`\>
47
+ > **bootstrap**(`nodeLoggingComponentType?`): `Promise`\<`boolean`\>
52
48
 
53
49
  Initialize the Cosmos DB environment.
54
50
 
55
51
  #### Parameters
56
52
 
57
- ##### nodeLoggingConnectorType?
53
+ ##### nodeLoggingComponentType?
58
54
 
59
55
  `string`
60
56
 
61
- Optional type of the logging connector.
57
+ Optional type of the logging component.
62
58
 
63
59
  #### Returns
64
60
 
@@ -194,7 +190,7 @@ Nothing.
194
190
 
195
191
  ### query()
196
192
 
197
- > **query**(`conditions?`, `sortProperties?`, `properties?`, `cursor?`, `pageSize?`): `Promise`\<\{ `entities`: `Partial`\<`T`\>[]; `cursor?`: `string`; \}\>
193
+ > **query**(`conditions?`, `sortProperties?`, `properties?`, `cursor?`, `limit?`): `Promise`\<\{ `entities`: `Partial`\<`T`\>[]; `cursor?`: `string`; \}\>
198
194
 
199
195
  Find all the entities which match the conditions.
200
196
 
@@ -222,9 +218,9 @@ The optional properties to return, defaults to all.
222
218
 
223
219
  `string`
224
220
 
225
- The cursor to request the next page of entities.
221
+ The cursor to request the next chunk of entities.
226
222
 
227
- ##### pageSize?
223
+ ##### limit?
228
224
 
229
225
  `number`
230
226
 
@@ -12,11 +12,11 @@ The schema for the entity.
12
12
 
13
13
  ***
14
14
 
15
- ### loggingConnectorType?
15
+ ### loggingComponentType?
16
16
 
17
- > `optional` **loggingConnectorType**: `string`
17
+ > `optional` **loggingComponentType**: `string`
18
18
 
19
- The type of logging connector to use.
19
+ The type of logging component to use.
20
20
 
21
21
  #### Default
22
22
 
package/locales/en.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "info": {
3
3
  "cosmosDbEntityStorageConnector": {
4
- "databaseCreating": "Database \"{databaseName}\" creating",
5
- "databaseExists": "Database \"{databaseName}\" created or it already exists",
6
- "containerExists": "Container \"{containerName}\" created or it already exists"
4
+ "databaseCreating": "Database \"{databaseId}\" creating",
5
+ "databaseExists": "Database \"{databaseId}\" created or it already exists",
6
+ "containerExists": "Container \"{containerId}\" created or it already exists"
7
7
  }
8
8
  },
9
9
  "error": {
@@ -17,7 +17,9 @@
17
17
  "sortSingle": "You can only sort by a single property",
18
18
  "sortNotIndexed": "The property \"{property}\" is not indexed and cannot be used for sorting",
19
19
  "containerNotExisting": "The expected container definition is undefined",
20
- "containerNotCreated": "The container couldn't be created"
20
+ "containerCreateFailed": "The container couldn't be created \"{containerId}\"",
21
+ "databaseCreateFailed": "Unable to create database \"{databaseId}\"",
22
+ "containerDoesNotExist": "Container \"{containerId}\" does not exist"
21
23
  }
22
24
  }
23
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/entity-storage-connector-cosmosdb",
3
- "version": "0.0.2-next.1",
3
+ "version": "0.0.2-next.10",
4
4
  "description": "Entity Storage connector implementation using CosmosDB storage",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,11 +14,11 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@azure/cosmos": "4.4.1",
18
- "@azure/identity": "4.10.2",
17
+ "@azure/cosmos": "4.5.1",
18
+ "@azure/identity": "4.13.0",
19
19
  "@twin.org/core": "next",
20
20
  "@twin.org/entity": "next",
21
- "@twin.org/entity-storage-models": "0.0.2-next.1",
21
+ "@twin.org/entity-storage-models": "0.0.2-next.10",
22
22
  "@twin.org/logging-models": "next",
23
23
  "@twin.org/nameof": "next"
24
24
  },
@@ -39,5 +39,24 @@
39
39
  "dist/types",
40
40
  "locales",
41
41
  "docs"
42
- ]
42
+ ],
43
+ "keywords": [
44
+ "twin",
45
+ "trade",
46
+ "iota",
47
+ "framework",
48
+ "blockchain",
49
+ "entity-storage",
50
+ "entity",
51
+ "storage",
52
+ "persistence",
53
+ "database",
54
+ "connector",
55
+ "adapter",
56
+ "integration"
57
+ ],
58
+ "bugs": {
59
+ "url": "git+https://github.com/twinfoundation/entity-storage/issues"
60
+ },
61
+ "homepage": "https://twindev.org"
43
62
  }