@twin.org/api-tenant-processor 0.0.3-next.17 → 0.0.3-next.19

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 (66) hide show
  1. package/dist/es/entities/tenant.js +10 -2
  2. package/dist/es/entities/tenant.js.map +1 -1
  3. package/dist/es/index.js +10 -0
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/es/models/api/ITenantCreateRequest.js +2 -0
  6. package/dist/es/models/api/ITenantCreateRequest.js.map +1 -0
  7. package/dist/es/models/api/ITenantGetByApiKeyRequest.js +4 -0
  8. package/dist/es/models/api/ITenantGetByApiKeyRequest.js.map +1 -0
  9. package/dist/es/models/api/ITenantGetByIdRequest.js +4 -0
  10. package/dist/es/models/api/ITenantGetByIdRequest.js.map +1 -0
  11. package/dist/es/models/api/ITenantGetByPublicOriginRequest.js +4 -0
  12. package/dist/es/models/api/ITenantGetByPublicOriginRequest.js.map +1 -0
  13. package/dist/es/models/api/ITenantGetResponse.js +2 -0
  14. package/dist/es/models/api/ITenantGetResponse.js.map +1 -0
  15. package/dist/es/models/api/ITenantListRequest.js +4 -0
  16. package/dist/es/models/api/ITenantListRequest.js.map +1 -0
  17. package/dist/es/models/api/ITenantListResponse.js +2 -0
  18. package/dist/es/models/api/ITenantListResponse.js.map +1 -0
  19. package/dist/es/models/api/ITenantRemoveRequest.js +4 -0
  20. package/dist/es/models/api/ITenantRemoveRequest.js.map +1 -0
  21. package/dist/es/models/api/ITenantUpdateRequest.js +2 -0
  22. package/dist/es/models/api/ITenantUpdateRequest.js.map +1 -0
  23. package/dist/es/restEntryPoints.js +10 -0
  24. package/dist/es/restEntryPoints.js.map +1 -0
  25. package/dist/es/tenantAdminService.js +74 -16
  26. package/dist/es/tenantAdminService.js.map +1 -1
  27. package/dist/es/tenantRoutes.js +398 -0
  28. package/dist/es/tenantRoutes.js.map +1 -0
  29. package/dist/types/entities/tenant.d.ts +4 -0
  30. package/dist/types/index.d.ts +10 -0
  31. package/dist/types/models/api/ITenantCreateRequest.d.ts +12 -0
  32. package/dist/types/models/api/ITenantGetByApiKeyRequest.d.ts +14 -0
  33. package/dist/types/models/api/ITenantGetByIdRequest.d.ts +14 -0
  34. package/dist/types/models/api/ITenantGetByPublicOriginRequest.d.ts +14 -0
  35. package/dist/types/models/api/ITenantGetResponse.d.ts +10 -0
  36. package/dist/types/models/api/ITenantListRequest.d.ts +18 -0
  37. package/dist/types/models/api/ITenantListResponse.d.ts +17 -0
  38. package/dist/types/models/api/ITenantRemoveRequest.d.ts +14 -0
  39. package/dist/types/models/api/ITenantUpdateRequest.d.ts +19 -0
  40. package/dist/types/restEntryPoints.d.ts +2 -0
  41. package/dist/types/tenantAdminService.d.ts +21 -10
  42. package/dist/types/tenantRoutes.d.ts +77 -0
  43. package/docs/changelog.md +28 -0
  44. package/docs/reference/classes/Tenant.md +8 -0
  45. package/docs/reference/classes/TenantAdminService.md +54 -16
  46. package/docs/reference/functions/generateRestRoutesTenants.md +25 -0
  47. package/docs/reference/functions/tenantByApiKey.md +31 -0
  48. package/docs/reference/functions/tenantById.md +31 -0
  49. package/docs/reference/functions/tenantByPublicOrigin.md +31 -0
  50. package/docs/reference/functions/tenantCreate.md +31 -0
  51. package/docs/reference/functions/tenantList.md +31 -0
  52. package/docs/reference/functions/tenantRemove.md +31 -0
  53. package/docs/reference/functions/tenantUpdate.md +31 -0
  54. package/docs/reference/index.md +21 -0
  55. package/docs/reference/interfaces/ITenantCreateRequest.md +17 -0
  56. package/docs/reference/interfaces/ITenantGetByApiKeyRequest.md +17 -0
  57. package/docs/reference/interfaces/ITenantGetByIdRequest.md +17 -0
  58. package/docs/reference/interfaces/ITenantGetByPublicOriginRequest.md +17 -0
  59. package/docs/reference/interfaces/ITenantGetResponse.md +11 -0
  60. package/docs/reference/interfaces/ITenantListRequest.md +23 -0
  61. package/docs/reference/interfaces/ITenantListResponse.md +23 -0
  62. package/docs/reference/interfaces/ITenantRemoveRequest.md +17 -0
  63. package/docs/reference/interfaces/ITenantUpdateRequest.md +25 -0
  64. package/docs/reference/variables/tagsTenants.md +5 -0
  65. package/locales/en.json +2 -1
  66. package/package.json +2 -2
@@ -21,6 +21,10 @@ let Tenant = class Tenant {
21
21
  * The date the tenant was created.
22
22
  */
23
23
  dateCreated;
24
+ /**
25
+ * The date the tenant was modified.
26
+ */
27
+ dateModified;
24
28
  /**
25
29
  * The origin available to the public for accessing the API.
26
30
  */
@@ -35,7 +39,7 @@ __decorate([
35
39
  __metadata("design:type", String)
36
40
  ], Tenant.prototype, "id", void 0);
37
41
  __decorate([
38
- property({ type: "string" }),
42
+ property({ type: "string", isSecondary: true }),
39
43
  __metadata("design:type", String)
40
44
  ], Tenant.prototype, "apiKey", void 0);
41
45
  __decorate([
@@ -47,7 +51,11 @@ __decorate([
47
51
  __metadata("design:type", String)
48
52
  ], Tenant.prototype, "dateCreated", void 0);
49
53
  __decorate([
50
- property({ type: "string", optional: true }),
54
+ property({ type: "string" }),
55
+ __metadata("design:type", String)
56
+ ], Tenant.prototype, "dateModified", void 0);
57
+ __decorate([
58
+ property({ type: "string", optional: true, isSecondary: true }),
51
59
  __metadata("design:type", String)
52
60
  ], Tenant.prototype, "publicOrigin", void 0);
53
61
  __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../../src/entities/tenant.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAM;IAClB;;OAEG;IAEI,EAAE,CAAU;IAEnB;;OAEG;IAEI,MAAM,CAAU;IAEvB;;OAEG;IAEI,KAAK,CAAU;IAEtB;;OAEG;IAEI,WAAW,CAAU;IAE5B;;OAEG;IAEI,YAAY,CAAU;IAE7B;;OAEG;IAEI,YAAY,CAAW;CAC9B,CAAA;AA/BO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;kCAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;sCACN;AAMhB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;qCACP;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;2CACD;AAMrB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;4CAChB;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;4CACA;AAnClB,MAAM;IADlB,MAAM,EAAE;GACI,MAAM,CAoClB","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@twin.org/entity\";\n\n/**\n * Class defining the storage for node tenants.\n */\n@entity()\nexport class Tenant {\n\t/**\n\t * The unique identifier for the tenant.\n\t */\n\t@property({ type: \"string\", isPrimary: true })\n\tpublic id!: string;\n\n\t/**\n\t * The api key for the tenant.\n\t */\n\t@property({ type: \"string\" })\n\tpublic apiKey!: string;\n\n\t/**\n\t * The label of the tenant.\n\t */\n\t@property({ type: \"string\" })\n\tpublic label!: string;\n\n\t/**\n\t * The date the tenant was created.\n\t */\n\t@property({ type: \"string\" })\n\tpublic dateCreated!: string;\n\n\t/**\n\t * The origin available to the public for accessing the API.\n\t */\n\t@property({ type: \"string\", optional: true })\n\tpublic publicOrigin?: string;\n\n\t/**\n\t * Indicates whether the tenant is the node tenant.\n\t */\n\t@property({ type: \"boolean\" })\n\tpublic isNodeTenant!: boolean;\n}\n"]}
1
+ {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../../src/entities/tenant.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAM;IAClB;;OAEG;IAEI,EAAE,CAAU;IAEnB;;OAEG;IAEI,MAAM,CAAU;IAEvB;;OAEG;IAEI,KAAK,CAAU;IAEtB;;OAEG;IAEI,WAAW,CAAU;IAE5B;;OAEG;IAEI,YAAY,CAAU;IAE7B;;OAEG;IAEI,YAAY,CAAU;IAE7B;;OAEG;IAEI,YAAY,CAAW;CAC9B,CAAA;AArCO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;kCAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;sCACzB;AAMhB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;qCACP;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;2CACD;AAMrB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;4CACA;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;4CACnC;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;4CACA;AAzClB,MAAM;IADlB,MAAM,EAAE;GACI,MAAM,CA0ClB","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@twin.org/entity\";\n\n/**\n * Class defining the storage for node tenants.\n */\n@entity()\nexport class Tenant {\n\t/**\n\t * The unique identifier for the tenant.\n\t */\n\t@property({ type: \"string\", isPrimary: true })\n\tpublic id!: string;\n\n\t/**\n\t * The api key for the tenant.\n\t */\n\t@property({ type: \"string\", isSecondary: true })\n\tpublic apiKey!: string;\n\n\t/**\n\t * The label of the tenant.\n\t */\n\t@property({ type: \"string\" })\n\tpublic label!: string;\n\n\t/**\n\t * The date the tenant was created.\n\t */\n\t@property({ type: \"string\" })\n\tpublic dateCreated!: string;\n\n\t/**\n\t * The date the tenant was modified.\n\t */\n\t@property({ type: \"string\" })\n\tpublic dateModified!: string;\n\n\t/**\n\t * The origin available to the public for accessing the API.\n\t */\n\t@property({ type: \"string\", optional: true, isSecondary: true })\n\tpublic publicOrigin?: string;\n\n\t/**\n\t * Indicates whether the tenant is the node tenant.\n\t */\n\t@property({ type: \"boolean\" })\n\tpublic isNodeTenant!: boolean;\n}\n"]}
package/dist/es/index.js CHANGED
@@ -1,6 +1,15 @@
1
1
  // Copyright 2025 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
3
  export * from "./entities/tenant.js";
4
+ export * from "./models/api/ITenantCreateRequest.js";
5
+ export * from "./models/api/ITenantGetByApiKeyRequest.js";
6
+ export * from "./models/api/ITenantGetByIdRequest.js";
7
+ export * from "./models/api/ITenantGetByPublicOriginRequest.js";
8
+ export * from "./models/api/ITenantGetResponse.js";
9
+ export * from "./models/api/ITenantListRequest.js";
10
+ export * from "./models/api/ITenantListResponse.js";
11
+ export * from "./models/api/ITenantRemoveRequest.js";
12
+ export * from "./models/api/ITenantUpdateRequest.js";
4
13
  export * from "./models/ITenantAdminServiceConfig.js";
5
14
  export * from "./models/ITenantAdminServiceConstructorOptions.js";
6
15
  export * from "./models/ITenantProcessorConfig.js";
@@ -9,5 +18,6 @@ export * from "./schema.js";
9
18
  export * from "./tenantAdminService.js";
10
19
  export * from "./tenantIdContextIdHandler.js";
11
20
  export * from "./tenantProcessor.js";
21
+ export * from "./tenantRoutes.js";
12
22
  export * from "./utils/tenantIdHelper.js";
13
23
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uCAAuC,CAAC;AACtD,cAAc,mDAAmD,CAAC;AAClE,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./entities/tenant.js\";\nexport * from \"./models/ITenantAdminServiceConfig.js\";\nexport * from \"./models/ITenantAdminServiceConstructorOptions.js\";\nexport * from \"./models/ITenantProcessorConfig.js\";\nexport * from \"./models/ITenantProcessorConstructorOptions.js\";\nexport * from \"./schema.js\";\nexport * from \"./tenantAdminService.js\";\nexport * from \"./tenantIdContextIdHandler.js\";\nexport * from \"./tenantProcessor.js\";\nexport * from \"./utils/tenantIdHelper.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sCAAsC,CAAC;AACrD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,uCAAuC,CAAC;AACtD,cAAc,iDAAiD,CAAC;AAChE,cAAc,oCAAoC,CAAC;AACnD,cAAc,oCAAoC,CAAC;AACnD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,mDAAmD,CAAC;AAClE,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./entities/tenant.js\";\nexport * from \"./models/api/ITenantCreateRequest.js\";\nexport * from \"./models/api/ITenantGetByApiKeyRequest.js\";\nexport * from \"./models/api/ITenantGetByIdRequest.js\";\nexport * from \"./models/api/ITenantGetByPublicOriginRequest.js\";\nexport * from \"./models/api/ITenantGetResponse.js\";\nexport * from \"./models/api/ITenantListRequest.js\";\nexport * from \"./models/api/ITenantListResponse.js\";\nexport * from \"./models/api/ITenantRemoveRequest.js\";\nexport * from \"./models/api/ITenantUpdateRequest.js\";\nexport * from \"./models/ITenantAdminServiceConfig.js\";\nexport * from \"./models/ITenantAdminServiceConstructorOptions.js\";\nexport * from \"./models/ITenantProcessorConfig.js\";\nexport * from \"./models/ITenantProcessorConstructorOptions.js\";\nexport * from \"./schema.js\";\nexport * from \"./tenantAdminService.js\";\nexport * from \"./tenantIdContextIdHandler.js\";\nexport * from \"./tenantProcessor.js\";\nexport * from \"./tenantRoutes.js\";\nexport * from \"./utils/tenantIdHelper.js\";\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ITenantCreateRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantCreateRequest.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantCreateRequest.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@twin.org/api-models\";\n\n/**\n * The tenant to create.\n */\nexport interface ITenantCreateRequest {\n\t/**\n\t * The tenant to create.\n\t */\n\tbody: Omit<ITenant, \"id\" | \"dateCreated\" | \"dateModified\"> & { id?: string };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=ITenantGetByApiKeyRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantGetByApiKeyRequest.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantGetByApiKeyRequest.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * The tenant to get by API key.\n */\nexport interface ITenantGetByApiKeyRequest {\n\t/**\n\t * The path parameters.\n\t */\n\tpathParams: {\n\t\t/**\n\t\t * The API key of the tenant to get.\n\t\t */\n\t\tapiKey: string;\n\t};\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=ITenantGetByIdRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantGetByIdRequest.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantGetByIdRequest.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * The tenant to get by id.\n */\nexport interface ITenantGetByIdRequest {\n\t/**\n\t * The path parameters.\n\t */\n\tpathParams: {\n\t\t/**\n\t\t * The id of the tenant to get.\n\t\t */\n\t\tid: string;\n\t};\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=ITenantGetByPublicOriginRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantGetByPublicOriginRequest.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantGetByPublicOriginRequest.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * The tenant to get by public origin.\n */\nexport interface ITenantGetByPublicOriginRequest {\n\t/**\n\t * The path parameters.\n\t */\n\tpathParams: {\n\t\t/**\n\t\t * The public origin of the tenant to get.\n\t\t */\n\t\tpublicOrigin: string;\n\t};\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ITenantGetResponse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantGetResponse.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantGetResponse.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@twin.org/api-models\";\n\n/**\n * The tenant get response.\n */\nexport interface ITenantGetResponse {\n\t/**\n\t * The tenant.\n\t */\n\tbody: ITenant;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=ITenantListRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantListRequest.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantListRequest.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * The list of tenants.\n */\nexport interface ITenantListRequest {\n\t/**\n\t * The query parameters.\n\t */\n\tquery: {\n\t\t/**\n\t\t * The cursor to get the next chunk of tenants.\n\t\t */\n\t\tcursor?: string;\n\n\t\t/**\n\t\t * The number of tenants to return.\n\t\t */\n\t\tlimit?: string;\n\t};\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ITenantListResponse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantListResponse.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantListResponse.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@twin.org/api-models\";\nimport type { HeaderTypes } from \"@twin.org/web\";\n\n/**\n * The list of tenants.\n */\nexport interface ITenantListResponse {\n\t/**\n\t * The headers which can be used to include the cursor.\n\t */\n\theaders?: {\n\t\t[HeaderTypes.Link]?: string | string[];\n\t};\n\n\t/**\n\t * The list of tenants.\n\t */\n\tbody: ITenant[];\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=ITenantRemoveRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantRemoveRequest.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantRemoveRequest.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * The tenant to remove by id.\n */\nexport interface ITenantRemoveRequest {\n\t/**\n\t * The path parameters.\n\t */\n\tpathParams: {\n\t\t/**\n\t\t * The id of the tenant to remove.\n\t\t */\n\t\tid: string;\n\t};\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ITenantUpdateRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITenantUpdateRequest.js","sourceRoot":"","sources":["../../../../src/models/api/ITenantUpdateRequest.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@twin.org/api-models\";\n\n/**\n * The tenant to update.\n */\nexport interface ITenantUpdateRequest {\n\t/**\n\t * The path parameters.\n\t */\n\tpathParams: {\n\t\t/**\n\t\t * The id of the tenant to update.\n\t\t */\n\t\tid: string;\n\t};\n\n\t/**\n\t * The tenant to update.\n\t */\n\tbody: Omit<ITenant, \"id\" | \"dateCreated\" | \"dateModified\">;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { generateRestRoutesTenants, tagsTenants } from "./tenantRoutes.js";
2
+ export const restEntryPoints = [
3
+ {
4
+ name: "tenants",
5
+ defaultBaseRoute: "tenants",
6
+ tags: tagsTenants,
7
+ generateRoutes: generateRestRoutesTenants
8
+ }
9
+ ];
10
+ //# sourceMappingURL=restEntryPoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restEntryPoints.js","sourceRoot":"","sources":["../../src/restEntryPoints.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE3E,MAAM,CAAC,MAAM,eAAe,GAA2B;IACtD;QACC,IAAI,EAAE,SAAS;QACf,gBAAgB,EAAE,SAAS;QAC3B,IAAI,EAAE,WAAW;QACjB,cAAc,EAAE,yBAAyB;KACzC;CACD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IRestRouteEntryPoint } from \"@twin.org/api-models\";\nimport { generateRestRoutesTenants, tagsTenants } from \"./tenantRoutes.js\";\n\nexport const restEntryPoints: IRestRouteEntryPoint[] = [\n\t{\n\t\tname: \"tenants\",\n\t\tdefaultBaseRoute: \"tenants\",\n\t\ttags: tagsTenants,\n\t\tgenerateRoutes: generateRestRoutesTenants\n\t}\n];\n"]}
@@ -1,7 +1,8 @@
1
- import { GeneralError, Guards, Is, Url } from "@twin.org/core";
1
+ import { GeneralError, Guards, Is, Url, NotFoundError } from "@twin.org/core";
2
2
  import { ComparisonOperator } from "@twin.org/entity";
3
3
  import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
4
4
  import { Tenant } from "./entities/tenant.js";
5
+ import { TenantIdHelper } from "./utils/tenantIdHelper.js";
5
6
  /**
6
7
  * Service for performing email messaging operations to a connector.
7
8
  */
@@ -32,7 +33,8 @@ export class TenantAdminService {
32
33
  /**
33
34
  * Get a tenant by its id.
34
35
  * @param tenantId The id of the tenant.
35
- * @returns The tenant or undefined if not found.
36
+ * @returns The tenant.
37
+ * @throws Error if the tenant is not found.
36
38
  */
37
39
  async get(tenantId) {
38
40
  Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenantId", tenantId, 32);
@@ -41,12 +43,16 @@ export class TenantAdminService {
41
43
  tenant = await this._entityStorageConnector.get(tenantId);
42
44
  }
43
45
  catch { }
46
+ if (!Is.object(tenant)) {
47
+ throw new NotFoundError(TenantAdminService.CLASS_NAME, "tenantNotFound", tenantId);
48
+ }
44
49
  return tenant;
45
50
  }
46
51
  /**
47
52
  * Get a tenant by its api key.
48
53
  * @param apiKey The api key of the tenant.
49
- * @returns The tenant or undefined if not found.
54
+ * @returns The tenant.
55
+ * @throws Error if the tenant is not found.
50
56
  */
51
57
  async getByApiKey(apiKey) {
52
58
  Guards.stringHexLength(TenantAdminService.CLASS_NAME, "apiKey", apiKey, 32);
@@ -55,12 +61,16 @@ export class TenantAdminService {
55
61
  tenant = await this._entityStorageConnector.get(apiKey, "apiKey");
56
62
  }
57
63
  catch { }
64
+ if (!Is.object(tenant)) {
65
+ throw new NotFoundError(TenantAdminService.CLASS_NAME, "tenantNotFound", apiKey);
66
+ }
58
67
  return tenant;
59
68
  }
60
69
  /**
61
70
  * Get a tenant by its public origin.
62
- * @param publicOrigin The public origin of the tenant.
63
- * @returns The tenant or undefined if not found.
71
+ * @param publicOrigin The origin of the tenant.
72
+ * @returns The tenant.
73
+ * @throws Error if the tenant is not found.
64
74
  */
65
75
  async getByPublicOrigin(publicOrigin) {
66
76
  Guards.stringValue(TenantAdminService.CLASS_NAME, "publicOrigin", publicOrigin);
@@ -69,17 +79,24 @@ export class TenantAdminService {
69
79
  tenant = await this._entityStorageConnector.get(publicOrigin, "publicOrigin");
70
80
  }
71
81
  catch { }
82
+ if (!Is.object(tenant)) {
83
+ throw new NotFoundError(TenantAdminService.CLASS_NAME, "tenantNotFound", publicOrigin);
84
+ }
72
85
  return tenant;
73
86
  }
74
87
  /**
75
- * Set a tenant.
88
+ * Create a tenant.
76
89
  * @param tenant The tenant to store.
77
- * @returns Nothing.
90
+ * @returns The tenant id.
78
91
  */
79
- async set(tenant) {
92
+ async create(tenant) {
80
93
  Guards.objectValue(TenantAdminService.CLASS_NAME, "tenant", tenant);
81
- Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.id", tenant.id, 32);
82
- Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.apiKey", tenant.apiKey, 32);
94
+ if (Is.stringValue(tenant.id)) {
95
+ Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.id", tenant.id, 32);
96
+ }
97
+ if (Is.stringValue(tenant.apiKey)) {
98
+ Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.apiKey", tenant.apiKey, 32);
99
+ }
83
100
  let publicOrigin;
84
101
  if (Is.stringValue(tenant.publicOrigin)) {
85
102
  Url.guard(TenantAdminService.CLASS_NAME, "tenant.publicOrigin", tenant.publicOrigin);
@@ -87,19 +104,60 @@ export class TenantAdminService {
87
104
  const parts = url.parts();
88
105
  publicOrigin = `${parts.schema}://${parts.host}${Is.integer(parts.port) ? `:${parts.port}` : ""}`;
89
106
  }
90
- const existingApiKey = await this.getByApiKey(tenant.apiKey);
91
- if (existingApiKey && existingApiKey.id !== tenant.id) {
92
- throw new GeneralError(TenantAdminService.CLASS_NAME, "apiKeyAlreadyInUse");
107
+ if (Is.stringValue(tenant.apiKey)) {
108
+ const existingApiKey = await this._entityStorageConnector.get(tenant.apiKey, "apiKey");
109
+ if (Is.object(existingApiKey) && existingApiKey.id !== tenant.id) {
110
+ throw new GeneralError(TenantAdminService.CLASS_NAME, "apiKeyAlreadyInUse");
111
+ }
93
112
  }
94
113
  const tenantEntity = new Tenant();
95
- tenantEntity.id = tenant.id;
96
- tenantEntity.apiKey = tenant.apiKey;
114
+ tenantEntity.id = tenant.id ?? TenantIdHelper.generateTenantId();
115
+ tenantEntity.apiKey = tenant.apiKey ?? TenantIdHelper.generateApiKey();
97
116
  tenantEntity.dateCreated = new Date(Date.now()).toISOString();
117
+ tenantEntity.dateModified = tenantEntity.dateCreated;
98
118
  tenantEntity.label = tenant.label;
99
- tenantEntity.dateCreated = new Date(Date.now()).toISOString();
100
119
  tenantEntity.publicOrigin = publicOrigin;
101
120
  tenantEntity.isNodeTenant = tenant.isNodeTenant;
102
121
  await this._entityStorageConnector.set(tenantEntity);
122
+ return tenantEntity.id;
123
+ }
124
+ /**
125
+ * Update a tenant.
126
+ * @param tenant The tenant to update.
127
+ * @returns The nothing.
128
+ */
129
+ async update(tenant) {
130
+ Guards.objectValue(TenantAdminService.CLASS_NAME, "tenant", tenant);
131
+ Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.id", tenant.id, 32);
132
+ if (Is.stringValue(tenant.apiKey)) {
133
+ Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.apiKey", tenant.apiKey, 32);
134
+ }
135
+ let publicOrigin;
136
+ if (Is.stringValue(tenant.publicOrigin)) {
137
+ Url.guard(TenantAdminService.CLASS_NAME, "tenant.publicOrigin", tenant.publicOrigin);
138
+ const url = new Url(tenant.publicOrigin);
139
+ const parts = url.parts();
140
+ publicOrigin = `${parts.schema}://${parts.host}${Is.integer(parts.port) ? `:${parts.port}` : ""}`;
141
+ }
142
+ const currentTenant = await this._entityStorageConnector.get(tenant.id);
143
+ if (!Is.object(currentTenant)) {
144
+ throw new NotFoundError(TenantAdminService.CLASS_NAME, "tenantNotFound", tenant.id);
145
+ }
146
+ if (Is.stringValue(tenant.apiKey)) {
147
+ const existingApiKey = await this._entityStorageConnector.get(tenant.apiKey, "apiKey");
148
+ if (Is.object(existingApiKey) && existingApiKey.id !== currentTenant.id) {
149
+ throw new GeneralError(TenantAdminService.CLASS_NAME, "apiKeyAlreadyInUse");
150
+ }
151
+ }
152
+ const tenantEntity = new Tenant();
153
+ tenantEntity.id = tenant.id;
154
+ tenantEntity.apiKey = tenant.apiKey ?? currentTenant.apiKey;
155
+ tenantEntity.dateCreated = currentTenant.dateCreated;
156
+ tenantEntity.dateModified = new Date(Date.now()).toISOString();
157
+ tenantEntity.label = tenant.label ?? currentTenant.label;
158
+ tenantEntity.publicOrigin = publicOrigin ?? currentTenant.publicOrigin;
159
+ tenantEntity.isNodeTenant = tenant.isNodeTenant ?? currentTenant.isNodeTenant;
160
+ await this._entityStorageConnector.set(tenantEntity);
103
161
  }
104
162
  /**
105
163
  * Remove a tenant by its id.
@@ -1 +1 @@
1
- {"version":3,"file":"tenantAdminService.js","sourceRoot":"","sources":["../../src/tenantAdminService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenantAdminComponent, ITenant } from \"@twin.org/api-models\";\nimport { GeneralError, Guards, Is, Url } from \"@twin.org/core\";\nimport { ComparisonOperator } from \"@twin.org/entity\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { Tenant } from \"./entities/tenant.js\";\nimport type { ITenantAdminServiceConstructorOptions } from \"./models/ITenantAdminServiceConstructorOptions.js\";\n\n/**\n * Service for performing email messaging operations to a connector.\n */\nexport class TenantAdminService implements ITenantAdminComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TenantAdminService>();\n\n\t/**\n\t * Entity storage connector used by the service.\n\t * @internal\n\t */\n\tprivate readonly _entityStorageConnector: IEntityStorageConnector<Tenant>;\n\n\t/**\n\t * Create a new instance of TenantAdminService.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options?: ITenantAdminServiceConstructorOptions) {\n\t\tthis._entityStorageConnector = EntityStorageConnectorFactory.get(\n\t\t\toptions?.tenantEntityStorageType ?? \"tenant\"\n\t\t);\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TenantAdminService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async get(tenantId: string): Promise<ITenant | undefined> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(tenantId);\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Get a tenant by its api key.\n\t * @param apiKey The api key of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async getByApiKey(apiKey: string): Promise<ITenant | undefined> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(apiKey), apiKey, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Get a tenant by its public origin.\n\t * @param publicOrigin The public origin of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async getByPublicOrigin(publicOrigin: string): Promise<ITenant | undefined> {\n\t\tGuards.stringValue(TenantAdminService.CLASS_NAME, nameof(publicOrigin), publicOrigin);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(publicOrigin, \"publicOrigin\");\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Set a tenant.\n\t * @param tenant The tenant to store.\n\t * @returns Nothing.\n\t */\n\tpublic async set(tenant: ITenant): Promise<void> {\n\t\tGuards.objectValue<ITenant>(TenantAdminService.CLASS_NAME, nameof(tenant), tenant);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.id), tenant.id, 32);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.apiKey), tenant.apiKey, 32);\n\n\t\tlet publicOrigin: string | undefined;\n\t\tif (Is.stringValue(tenant.publicOrigin)) {\n\t\t\tUrl.guard(TenantAdminService.CLASS_NAME, nameof(tenant.publicOrigin), tenant.publicOrigin);\n\n\t\t\tconst url = new Url(tenant.publicOrigin);\n\t\t\tconst parts = url.parts();\n\t\t\tpublicOrigin = `${parts.schema}://${parts.host}${Is.integer(parts.port) ? `:${parts.port}` : \"\"}`;\n\t\t}\n\n\t\tconst existingApiKey = await this.getByApiKey(tenant.apiKey);\n\t\tif (existingApiKey && existingApiKey.id !== tenant.id) {\n\t\t\tthrow new GeneralError(TenantAdminService.CLASS_NAME, \"apiKeyAlreadyInUse\");\n\t\t}\n\n\t\tconst tenantEntity = new Tenant();\n\t\ttenantEntity.id = tenant.id;\n\t\ttenantEntity.apiKey = tenant.apiKey;\n\t\ttenantEntity.dateCreated = new Date(Date.now()).toISOString();\n\t\ttenantEntity.label = tenant.label;\n\t\ttenantEntity.dateCreated = new Date(Date.now()).toISOString();\n\t\ttenantEntity.publicOrigin = publicOrigin;\n\t\ttenantEntity.isNodeTenant = tenant.isNodeTenant;\n\n\t\tawait this._entityStorageConnector.set(tenantEntity);\n\t}\n\n\t/**\n\t * Remove a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(tenantId: string): Promise<void> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\treturn this._entityStorageConnector.remove(tenantId);\n\t}\n\n\t/**\n\t * Query tenants with pagination.\n\t * @param options Optional query options.\n\t * @param options.isNodeTenant Whether to filter for node admin tenants.\n\t * @param cursor The cursor to start from.\n\t * @param limit The maximum number of tenants to return.\n\t * @returns The tenants and the next cursor if more tenants are available.\n\t */\n\tpublic async query(\n\t\toptions?: { isNodeTenant?: boolean },\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ tenants: ITenant[]; cursor?: string }> {\n\t\tconst conditions = [];\n\n\t\tif (Is.boolean(options?.isNodeTenant)) {\n\t\t\tconditions.push({\n\t\t\t\tproperty: \"isNodeTenant\",\n\t\t\t\tvalue: options.isNodeTenant,\n\t\t\t\tcomparison: ComparisonOperator.Equals\n\t\t\t});\n\t\t}\n\n\t\tconst result = await this._entityStorageConnector.query(\n\t\t\tconditions.length > 0 ? { conditions } : undefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tcursor,\n\t\t\tlimit\n\t\t);\n\n\t\treturn {\n\t\t\ttenants: result.entities as ITenant[],\n\t\t\tcursor: result.cursor\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"tenantAdminService.js","sourceRoot":"","sources":["../../src/tenantAdminService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenantAdminComponent, ITenant } from \"@twin.org/api-models\";\nimport { GeneralError, Guards, Is, Url, NotFoundError } from \"@twin.org/core\";\nimport { ComparisonOperator } from \"@twin.org/entity\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { Tenant } from \"./entities/tenant.js\";\nimport type { ITenantAdminServiceConstructorOptions } from \"./models/ITenantAdminServiceConstructorOptions.js\";\nimport { TenantIdHelper } from \"./utils/tenantIdHelper.js\";\n\n/**\n * Service for performing email messaging operations to a connector.\n */\nexport class TenantAdminService implements ITenantAdminComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TenantAdminService>();\n\n\t/**\n\t * Entity storage connector used by the service.\n\t * @internal\n\t */\n\tprivate readonly _entityStorageConnector: IEntityStorageConnector<Tenant>;\n\n\t/**\n\t * Create a new instance of TenantAdminService.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options?: ITenantAdminServiceConstructorOptions) {\n\t\tthis._entityStorageConnector = EntityStorageConnectorFactory.get(\n\t\t\toptions?.tenantEntityStorageType ?? \"tenant\"\n\t\t);\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TenantAdminService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns The tenant.\n\t * @throws Error if the tenant is not found.\n\t */\n\tpublic async get(tenantId: string): Promise<ITenant> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(tenantId);\n\t\t} catch {}\n\n\t\tif (!Is.object(tenant)) {\n\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", tenantId);\n\t\t}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Get a tenant by its api key.\n\t * @param apiKey The api key of the tenant.\n\t * @returns The tenant.\n\t * @throws Error if the tenant is not found.\n\t */\n\tpublic async getByApiKey(apiKey: string): Promise<ITenant> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(apiKey), apiKey, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\t\t} catch {}\n\n\t\tif (!Is.object(tenant)) {\n\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", apiKey);\n\t\t}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Get a tenant by its public origin.\n\t * @param publicOrigin The origin of the tenant.\n\t * @returns The tenant.\n\t * @throws Error if the tenant is not found.\n\t */\n\tpublic async getByPublicOrigin(publicOrigin: string): Promise<ITenant> {\n\t\tGuards.stringValue(TenantAdminService.CLASS_NAME, nameof(publicOrigin), publicOrigin);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(publicOrigin, \"publicOrigin\");\n\t\t} catch {}\n\n\t\tif (!Is.object(tenant)) {\n\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", publicOrigin);\n\t\t}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Create a tenant.\n\t * @param tenant The tenant to store.\n\t * @returns The tenant id.\n\t */\n\tpublic async create(\n\t\ttenant: Omit<ITenant, \"id\" | \"dateCreated\" | \"dateModified\"> & { id?: string }\n\t): Promise<string> {\n\t\tGuards.objectValue<ITenant>(TenantAdminService.CLASS_NAME, nameof(tenant), tenant);\n\t\tif (Is.stringValue(tenant.id)) {\n\t\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.id), tenant.id, 32);\n\t\t}\n\t\tif (Is.stringValue(tenant.apiKey)) {\n\t\t\tGuards.stringHexLength(\n\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\tnameof(tenant.apiKey),\n\t\t\t\ttenant.apiKey,\n\t\t\t\t32\n\t\t\t);\n\t\t}\n\n\t\tlet publicOrigin: string | undefined;\n\t\tif (Is.stringValue(tenant.publicOrigin)) {\n\t\t\tUrl.guard(TenantAdminService.CLASS_NAME, nameof(tenant.publicOrigin), tenant.publicOrigin);\n\n\t\t\tconst url = new Url(tenant.publicOrigin);\n\t\t\tconst parts = url.parts();\n\t\t\tpublicOrigin = `${parts.schema}://${parts.host}${Is.integer(parts.port) ? `:${parts.port}` : \"\"}`;\n\t\t}\n\n\t\tif (Is.stringValue(tenant.apiKey)) {\n\t\t\tconst existingApiKey = await this._entityStorageConnector.get(tenant.apiKey, \"apiKey\");\n\t\t\tif (Is.object(existingApiKey) && existingApiKey.id !== tenant.id) {\n\t\t\t\tthrow new GeneralError(TenantAdminService.CLASS_NAME, \"apiKeyAlreadyInUse\");\n\t\t\t}\n\t\t}\n\n\t\tconst tenantEntity = new Tenant();\n\t\ttenantEntity.id = tenant.id ?? TenantIdHelper.generateTenantId();\n\t\ttenantEntity.apiKey = tenant.apiKey ?? TenantIdHelper.generateApiKey();\n\t\ttenantEntity.dateCreated = new Date(Date.now()).toISOString();\n\t\ttenantEntity.dateModified = tenantEntity.dateCreated;\n\t\ttenantEntity.label = tenant.label;\n\t\ttenantEntity.publicOrigin = publicOrigin;\n\t\ttenantEntity.isNodeTenant = tenant.isNodeTenant;\n\n\t\tawait this._entityStorageConnector.set(tenantEntity);\n\n\t\treturn tenantEntity.id;\n\t}\n\n\t/**\n\t * Update a tenant.\n\t * @param tenant The tenant to update.\n\t * @returns The nothing.\n\t */\n\tpublic async update(\n\t\ttenant: Partial<Omit<ITenant, \"dateCreated\" | \"dateModified\">>\n\t): Promise<void> {\n\t\tGuards.objectValue<ITenant>(TenantAdminService.CLASS_NAME, nameof(tenant), tenant);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.id), tenant.id, 32);\n\t\tif (Is.stringValue(tenant.apiKey)) {\n\t\t\tGuards.stringHexLength(\n\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\tnameof(tenant.apiKey),\n\t\t\t\ttenant.apiKey,\n\t\t\t\t32\n\t\t\t);\n\t\t}\n\n\t\tlet publicOrigin: string | undefined;\n\t\tif (Is.stringValue(tenant.publicOrigin)) {\n\t\t\tUrl.guard(TenantAdminService.CLASS_NAME, nameof(tenant.publicOrigin), tenant.publicOrigin);\n\n\t\t\tconst url = new Url(tenant.publicOrigin);\n\t\t\tconst parts = url.parts();\n\t\t\tpublicOrigin = `${parts.schema}://${parts.host}${Is.integer(parts.port) ? `:${parts.port}` : \"\"}`;\n\t\t}\n\n\t\tconst currentTenant = await this._entityStorageConnector.get(tenant.id);\n\t\tif (!Is.object(currentTenant)) {\n\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", tenant.id);\n\t\t}\n\n\t\tif (Is.stringValue(tenant.apiKey)) {\n\t\t\tconst existingApiKey = await this._entityStorageConnector.get(tenant.apiKey, \"apiKey\");\n\t\t\tif (Is.object(existingApiKey) && existingApiKey.id !== currentTenant.id) {\n\t\t\t\tthrow new GeneralError(TenantAdminService.CLASS_NAME, \"apiKeyAlreadyInUse\");\n\t\t\t}\n\t\t}\n\n\t\tconst tenantEntity = new Tenant();\n\t\ttenantEntity.id = tenant.id;\n\t\ttenantEntity.apiKey = tenant.apiKey ?? currentTenant.apiKey;\n\t\ttenantEntity.dateCreated = currentTenant.dateCreated;\n\t\ttenantEntity.dateModified = new Date(Date.now()).toISOString();\n\t\ttenantEntity.label = tenant.label ?? currentTenant.label;\n\t\ttenantEntity.publicOrigin = publicOrigin ?? currentTenant.publicOrigin;\n\t\ttenantEntity.isNodeTenant = tenant.isNodeTenant ?? currentTenant.isNodeTenant;\n\n\t\tawait this._entityStorageConnector.set(tenantEntity);\n\t}\n\n\t/**\n\t * Remove a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(tenantId: string): Promise<void> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\treturn this._entityStorageConnector.remove(tenantId);\n\t}\n\n\t/**\n\t * Query tenants with pagination.\n\t * @param options Optional query options.\n\t * @param options.isNodeTenant Whether to filter for node admin tenants.\n\t * @param cursor The cursor to start from.\n\t * @param limit The maximum number of tenants to return.\n\t * @returns The tenants and the next cursor if more tenants are available.\n\t */\n\tpublic async query(\n\t\toptions?: { isNodeTenant?: boolean },\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ tenants: ITenant[]; cursor?: string }> {\n\t\tconst conditions = [];\n\n\t\tif (Is.boolean(options?.isNodeTenant)) {\n\t\t\tconditions.push({\n\t\t\t\tproperty: \"isNodeTenant\",\n\t\t\t\tvalue: options.isNodeTenant,\n\t\t\t\tcomparison: ComparisonOperator.Equals\n\t\t\t});\n\t\t}\n\n\t\tconst result = await this._entityStorageConnector.query(\n\t\t\tconditions.length > 0 ? { conditions } : undefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tcursor,\n\t\t\tlimit\n\t\t);\n\n\t\treturn {\n\t\t\ttenants: result.entities as ITenant[],\n\t\t\tcursor: result.cursor\n\t\t};\n\t}\n}\n"]}