@3sixty/api-tenant-processor 0.20.0-next.0 → 0.20.0-next.1
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/dist/es/entities/tenant.js.map +1 -1
- package/dist/es/entities/tenantV0.js.map +1 -1
- package/dist/es/entities/tenantV1.js.map +1 -1
- package/dist/es/index.js +4 -3
- package/dist/es/index.js.map +1 -1
- package/dist/es/models/ISingleTenantProcessorConfig.js.map +1 -1
- package/dist/es/models/ISingleTenantProcessorConstructorOptions.js.map +1 -1
- package/dist/es/models/ITenantAdminServiceConfig.js.map +1 -1
- package/dist/es/models/ITenantAdminServiceConstructorOptions.js.map +1 -1
- package/dist/es/models/ITenantProcessorConfig.js.map +1 -1
- package/dist/es/models/ITenantProcessorConstructorOptions.js.map +1 -1
- package/dist/es/models/api/ITenantCreateRequest.js.map +1 -1
- package/dist/es/models/api/ITenantGetByApiKeyRequest.js.map +1 -1
- package/dist/es/models/api/ITenantGetByIdRequest.js.map +1 -1
- package/dist/es/models/api/ITenantGetByPublicOriginRequest.js.map +1 -1
- package/dist/es/models/api/ITenantGetResponse.js.map +1 -1
- package/dist/es/models/api/ITenantListRequest.js.map +1 -1
- package/dist/es/models/api/ITenantListResponse.js.map +1 -1
- package/dist/es/models/api/ITenantRemoveRequest.js.map +1 -1
- package/dist/es/models/api/ITenantUpdateRequest.js.map +1 -1
- package/dist/es/restEntryPoints.js.map +1 -1
- package/dist/es/schema.js.map +1 -1
- package/dist/es/singleTenantProcessor.js.map +1 -1
- package/dist/es/tenantAdminService.js +12 -2
- package/dist/es/tenantAdminService.js.map +1 -1
- package/dist/es/tenantIdContextIdHandler.js.map +1 -1
- package/dist/es/tenantProcessor.js.map +1 -1
- package/dist/es/tenantRoutes.js +20 -7
- package/dist/es/tenantRoutes.js.map +1 -1
- package/dist/es/utils/tenantIdHelper.js.map +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/models/ITenantAdminServiceConstructorOptions.d.ts +5 -0
- package/docs/changelog.md +17 -0
- package/docs/reference/classes/SingleTenantProcessor.md +2 -0
- package/docs/reference/classes/TenantAdminService.md +1 -1
- package/docs/reference/classes/TenantProcessor.md +2 -0
- package/docs/reference/classes/TenantV0.md +61 -0
- package/docs/reference/classes/TenantV1.md +77 -0
- package/docs/reference/index.md +3 -3
- package/docs/reference/interfaces/ITenantAdminServiceConstructorOptions.md +14 -0
- package/docs/reference/variables/restEntryPoints.md +5 -0
- package/locales/en.json +0 -4
- package/package.json +2 -2
- package/dist/es/models/ITenantOverrideProcessorConfig.js +0 -4
- package/dist/es/models/ITenantOverrideProcessorConfig.js.map +0 -1
- package/dist/es/models/ITenantOverrideProcessorConstructorOptions.js +0 -2
- package/dist/es/models/ITenantOverrideProcessorConstructorOptions.js.map +0 -1
- package/dist/es/tenantOverrideProcessor.js +0 -119
- package/dist/es/tenantOverrideProcessor.js.map +0 -1
- package/dist/types/models/ITenantOverrideProcessorConfig.d.ts +0 -13
- package/dist/types/models/ITenantOverrideProcessorConstructorOptions.d.ts +0 -15
- package/dist/types/tenantOverrideProcessor.d.ts +0 -44
- package/docs/reference/classes/TenantOverrideProcessor.md +0 -119
- package/docs/reference/interfaces/ITenantOverrideProcessorConfig.md +0 -19
- package/docs/reference/interfaces/ITenantOverrideProcessorConstructorOptions.md +0 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant.js","
|
|
1
|
+
{"version":3,"file":"tenant.js","sources":["../../../src/entities/tenant.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAElD;;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,cAAc,CAAU;IAE/B;;OAEG;IAEI,oBAAoB,CAAY;CACvC,CAAA;AA3CO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;;kCAC1C;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;sCACxC;AAMhB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;;qCACvB;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;;2CACtB;AAMrB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;;4CACrB;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;4CAClD;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;8CACjC;AAMxB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;oDAC5C;AA/C3B,MAAM;IADlB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;GACV,MAAM,CAgDlB","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@3sixty/entity\";\n\n/**\n * Class defining the storage for node tenants.\n */\n@entity({ version: 2 })\nexport class Tenant {\n\t/**\n\t * The unique identifier for the tenant.\n\t */\n\t@property({ type: \"string\", isPrimary: true, maxLength: 32 })\n\tpublic id!: string;\n\n\t/**\n\t * The api key for the tenant.\n\t */\n\t@property({ type: \"string\", maxLength: 32, isSecondary: true })\n\tpublic apiKey!: string;\n\n\t/**\n\t * The label of the tenant.\n\t */\n\t@property({ type: \"string\", maxLength: 256 })\n\tpublic label!: string;\n\n\t/**\n\t * The date the tenant was created.\n\t */\n\t@property({ type: \"string\", format: \"date-time\" })\n\tpublic dateCreated!: string;\n\n\t/**\n\t * The date the tenant was modified.\n\t */\n\t@property({ type: \"string\", format: \"date-time\" })\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\", format: \"uri\", optional: true, isSecondary: true })\n\tpublic publicOrigin?: string;\n\n\t/**\n\t * The organization id for the tenant.\n\t */\n\t@property({ type: \"string\", maxLength: 255, isSecondary: true })\n\tpublic organizationId!: string;\n\n\t/**\n\t * Optional list of organization aliases that can be used for legacy lookups, indexed format.\n\t */\n\t@property({ type: \"array\", itemType: \"string\", optional: true, isSecondary: true })\n\tpublic organizationIdLegacy?: string[];\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenantV0.js","
|
|
1
|
+
{"version":3,"file":"tenantV0.js","sources":["../../../src/entities/tenantV0.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAElD;;GAEG;AAEI,IAAM,QAAQ,GAAd,MAAM,QAAQ;IACpB;;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;CAC7B,CAAA;AA/BO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;oCAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;wCACzB;AAMhB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;uCACP;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;6CACD;AAMrB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;8CACA;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;8CACnC;AAnCjB,QAAQ;IADpB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;GACV,QAAQ,CAoCpB","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@3sixty/entity\";\n\n/**\n * Class defining the storage for node tenants.\n */\n@entity({ version: 0 })\nexport class TenantV0 {\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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenantV1.js","
|
|
1
|
+
{"version":3,"file":"tenantV1.js","sources":["../../../src/entities/tenantV1.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAElD;;GAEG;AAEI,IAAM,QAAQ,GAAd,MAAM,QAAQ;IACpB;;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,cAAc,CAAU;IAE/B;;OAEG;IAEI,oBAAoB,CAAU;CACrC,CAAA;AA3CO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;oCAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;wCACzB;AAMhB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;uCACP;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;6CACD;AAMrB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;8CACA;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;8CACnC;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;gDACjB;AAMxB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;;sDAC3B;AA/CzB,QAAQ;IADpB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;GACV,QAAQ,CAgDpB","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@3sixty/entity\";\n\n/**\n * Class defining the storage for node tenants.\n */\n@entity({ version: 1 })\nexport class TenantV1 {\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 * The organization id for the tenant.\n\t */\n\t@property({ type: \"string\", isSecondary: true })\n\tpublic organizationId!: string;\n\n\t/**\n\t * Optional list of organization aliases that can be used for legacy lookups, indexed format.\n\t */\n\t@property({ type: \"string\", optional: true, isSecondary: true })\n\tpublic organizationIdLegacy?: string;\n}\n"]}
|
package/dist/es/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// Copyright 2025 IOTA Stiftung.
|
|
2
|
+
// Copyright 2026 3Sixty Trade Ltd.
|
|
2
3
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
4
|
export * from "./entities/tenant.js";
|
|
5
|
+
export * from "./entities/tenantV0.js";
|
|
6
|
+
export * from "./entities/tenantV1.js";
|
|
4
7
|
export * from "./models/api/ITenantCreateRequest.js";
|
|
5
8
|
export * from "./models/api/ITenantGetByApiKeyRequest.js";
|
|
6
9
|
export * from "./models/api/ITenantGetByIdRequest.js";
|
|
@@ -14,15 +17,13 @@ export * from "./models/ISingleTenantProcessorConfig.js";
|
|
|
14
17
|
export * from "./models/ISingleTenantProcessorConstructorOptions.js";
|
|
15
18
|
export * from "./models/ITenantAdminServiceConfig.js";
|
|
16
19
|
export * from "./models/ITenantAdminServiceConstructorOptions.js";
|
|
17
|
-
export * from "./models/ITenantOverrideProcessorConfig.js";
|
|
18
|
-
export * from "./models/ITenantOverrideProcessorConstructorOptions.js";
|
|
19
20
|
export * from "./models/ITenantProcessorConfig.js";
|
|
20
21
|
export * from "./models/ITenantProcessorConstructorOptions.js";
|
|
22
|
+
export * from "./restEntryPoints.js";
|
|
21
23
|
export * from "./schema.js";
|
|
22
24
|
export * from "./singleTenantProcessor.js";
|
|
23
25
|
export * from "./tenantAdminService.js";
|
|
24
26
|
export * from "./tenantIdContextIdHandler.js";
|
|
25
|
-
export * from "./tenantOverrideProcessor.js";
|
|
26
27
|
export * from "./tenantProcessor.js";
|
|
27
28
|
export * from "./tenantRoutes.js";
|
|
28
29
|
export * from "./utils/tenantIdHelper.js";
|
package/dist/es/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,mCAAmC;AACnC,uCAAuC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,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,0CAA0C,CAAC;AACzD,cAAc,sDAAsD,CAAC;AACrE,cAAc,uCAAuC,CAAC;AACtD,cAAc,mDAAmD,CAAC;AAClE,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,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// Copyright 2026 3Sixty Trade Ltd.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./entities/tenant.js\";\nexport * from \"./entities/tenantV0.js\";\nexport * from \"./entities/tenantV1.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/ISingleTenantProcessorConfig.js\";\nexport * from \"./models/ISingleTenantProcessorConstructorOptions.js\";\nexport * from \"./models/ITenantAdminServiceConfig.js\";\nexport * from \"./models/ITenantAdminServiceConstructorOptions.js\";\nexport * from \"./models/ITenantProcessorConfig.js\";\nexport * from \"./models/ITenantProcessorConstructorOptions.js\";\nexport * from \"./restEntryPoints.js\";\nexport * from \"./schema.js\";\nexport * from \"./singleTenantProcessor.js\";\nexport * from \"./tenantAdminService.js\";\nexport * from \"./tenantIdContextIdHandler.js\";\nexport * from \"./tenantProcessor.js\";\nexport * from \"./tenantRoutes.js\";\nexport * from \"./utils/tenantIdHelper.js\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ISingleTenantProcessorConfig.js","
|
|
1
|
+
{"version":3,"file":"ISingleTenantProcessorConfig.js","sources":["../../../src/models/ISingleTenantProcessorConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the single tenant processor\n */\nexport interface ISingleTenantProcessorConfig {\n\t/**\n\t * Include the stack with errors.\n\t */\n\tincludeErrorStack?: boolean;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ISingleTenantProcessorConstructorOptions.js","
|
|
1
|
+
{"version":3,"file":"ISingleTenantProcessorConstructorOptions.js","sources":["../../../src/models/ISingleTenantProcessorConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ISingleTenantProcessorConfig } from \"./ISingleTenantProcessorConfig.js\";\n\n/**\n * Options for the Single Tenant Processor constructor.\n */\nexport interface ISingleTenantProcessorConstructorOptions {\n\t/**\n\t * Configuration for the processor.\n\t */\n\tconfig?: ISingleTenantProcessorConfig;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantAdminServiceConfig.js","
|
|
1
|
+
{"version":3,"file":"ITenantAdminServiceConfig.js","sources":["../../../src/models/ITenantAdminServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the tenant admin service.\n */\nexport interface ITenantAdminServiceConfig {\n\t/**\n\t * The time in milliseconds a tenant is kept in the in-memory lookup cache, counted from when it\n\t * was read and not extended by use, set to 0 to disable caching. Entries are invalidated when a\n\t * tenant is created, updated or removed through this service, but only in the process that made\n\t * the change, so this is also the longest another node can serve a tenant that has been edited\n\t * elsewhere.\n\t * @default 30000\n\t */\n\ttenantCacheTtlMs?: number;\n\n\t/**\n\t * The maximum number of tenant lookups to hold in the in-memory cache.\n\t * @default undefined (LfuCache default)\n\t */\n\ttenantCacheCapacity?: number;\n\n\t/**\n\t * Maximum time in milliseconds to wait for the tenant cache mutex during a cache population.\n\t * @default undefined (LfuCache default)\n\t */\n\ttenantCacheMutexTimeoutMs?: number;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantAdminServiceConstructorOptions.js","
|
|
1
|
+
{"version":3,"file":"ITenantAdminServiceConstructorOptions.js","sources":["../../../src/models/ITenantAdminServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// Copyright 2026 3Sixty Trade Ltd.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenantAdminServiceConfig } from \"./ITenantAdminServiceConfig.js\";\n\n/**\n * Options for the Tenant Admin Service constructor.\n */\nexport interface ITenantAdminServiceConstructorOptions {\n\t/**\n\t * The entity storage for the tenants.\n\t * @default tenant\n\t */\n\ttenantEntityStorageType?: string;\n\n\t/**\n\t * The component type to use for firing tenant events.\n\t * @default platform\n\t */\n\tplatformComponentType?: string;\n\n\t/**\n\t * Configuration for the service.\n\t */\n\tconfig?: ITenantAdminServiceConfig;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantProcessorConfig.js","
|
|
1
|
+
{"version":3,"file":"ITenantProcessorConfig.js","sources":["../../../src/models/ITenantProcessorConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the tenant processor\n */\nexport interface ITenantProcessorConfig {\n\t/**\n\t * The key to look for in the header or query params for the api key.\n\t * @default x-api-key\n\t */\n\tapiKeyName?: string;\n\n\t/**\n\t * The list of endpoint paths that should be checked for an api key header, can be regexp strings. Defaults to [\"/login$\"].\n\t */\n\tapiKeyEndpoints?: string[];\n\n\t/**\n\t * Include the stack with errors.\n\t */\n\tincludeErrorStack?: boolean;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantProcessorConstructorOptions.js","
|
|
1
|
+
{"version":3,"file":"ITenantProcessorConstructorOptions.js","sources":["../../../src/models/ITenantProcessorConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenantProcessorConfig } from \"./ITenantProcessorConfig.js\";\n\n/**\n * Options for the Tenant Processor constructor.\n */\nexport interface ITenantProcessorConstructorOptions {\n\t/**\n\t * The component used to resolve tenants, which also provides the lookup caching.\n\t * @default tenant-admin\n\t */\n\ttenantAdminComponentType?: string;\n\n\t/**\n\t * Configuration for the processor.\n\t */\n\tconfig?: ITenantProcessorConfig;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantCreateRequest.js","
|
|
1
|
+
{"version":3,"file":"ITenantCreateRequest.js","sources":["../../../../src/models/api/ITenantCreateRequest.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@3sixty/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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantGetByApiKeyRequest.js","
|
|
1
|
+
{"version":3,"file":"ITenantGetByApiKeyRequest.js","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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantGetByIdRequest.js","
|
|
1
|
+
{"version":3,"file":"ITenantGetByIdRequest.js","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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantGetByPublicOriginRequest.js","
|
|
1
|
+
{"version":3,"file":"ITenantGetByPublicOriginRequest.js","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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantGetResponse.js","
|
|
1
|
+
{"version":3,"file":"ITenantGetResponse.js","sources":["../../../../src/models/api/ITenantGetResponse.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@3sixty/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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantListRequest.js","
|
|
1
|
+
{"version":3,"file":"ITenantListRequest.js","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 condition for the query as JSON version of EntityCondition type.\n\t\t */\n\t\tconditions?: string;\n\n\t\t/**\n\t\t * The properties to include in the returned tenants, separated by commas.\n\t\t * If not provided, all properties will be returned.\n\t\t */\n\t\tproperties?: string;\n\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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantListResponse.js","
|
|
1
|
+
{"version":3,"file":"ITenantListResponse.js","sources":["../../../../src/models/api/ITenantListResponse.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@3sixty/api-models\";\nimport type { HeaderTypes } from \"@3sixty/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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantRemoveRequest.js","
|
|
1
|
+
{"version":3,"file":"ITenantRemoveRequest.js","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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITenantUpdateRequest.js","
|
|
1
|
+
{"version":3,"file":"ITenantUpdateRequest.js","sources":["../../../../src/models/api/ITenantUpdateRequest.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenant } from \"@3sixty/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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restEntryPoints.js","
|
|
1
|
+
{"version":3,"file":"restEntryPoints.js","sources":["../../src/restEntryPoints.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE3E;;GAEG;AACH,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 \"@3sixty/api-models\";\nimport { generateRestRoutesTenants, tagsTenants } from \"./tenantRoutes.js\";\n\n/**\n * REST entry points for the tenant administration service.\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"]}
|
package/dist/es/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","
|
|
1
|
+
{"version":3,"file":"schema.js","sources":["../../src/schema.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD;;;GAGG;AACH,MAAM,UAAU,UAAU;IACzB,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACnF,mBAAmB,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvF,mBAAmB,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEvF,sBAAsB,CAAC,QAAQ,CAAC,GAAG,QAAQ,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACzD,uBAAuB,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE;YAC5E,IAAI,eAAe,CAAC,QAAQ,KAAK,sBAAsB,EAAE,CAAC;gBACzD,OAAO;YACR,CAAC;YACD,OAAO,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;KACD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,oBAAoB,CAAC,KAAc;IAC3C,IAAI,KAAgB,CAAC;IAErB,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,KAAK,GAAG,KAAK,CAAC;IACf,CAAC;SAAM,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,IAAI,CAAC;YACJ,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1C,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACR,KAAK,GAAG,EAAE,CAAC;QACZ,CAAC;IACF,CAAC;SAAM,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;SAAM,CAAC;QACP,KAAK,GAAG,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YACxC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACd,CAAC;IACF,CAAC;IAED,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACzC,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"@3sixty/core\";\nimport { EntitySchemaFactory, EntitySchemaHelper } from \"@3sixty/entity\";\nimport { SchemaMigrationFactory } from \"@3sixty/entity-storage-models\";\n\nimport { Tenant } from \"./entities/tenant.js\";\nimport { TenantV0 } from \"./entities/tenantV0.js\";\nimport { TenantV1 } from \"./entities/tenantV1.js\";\n\n/**\n * Initialize the schema for the node tenant processor, including the Tenant 1 to 2 migration\n * step which converts organizationIdLegacy from a pipe-delimited string to an array of ids.\n */\nexport function initSchema(): void {\n\tEntitySchemaFactory.register(\"Tenant\", () => EntitySchemaHelper.getSchema(Tenant));\n\tEntitySchemaFactory.register(\"TenantV0\", () => EntitySchemaHelper.getSchema(TenantV0));\n\tEntitySchemaFactory.register(\"TenantV1\", () => EntitySchemaHelper.getSchema(TenantV1));\n\n\tSchemaMigrationFactory.register(`${\"Tenant\"}_1_2`, () => ({\n\t\ttransformEntityProperty: (entity, schema1Property, schema2Property, value) => {\n\t\t\tif (schema2Property.property !== \"organizationIdLegacy\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn toOrganizationIdList(value);\n\t\t}\n\t}));\n}\n\n/**\n * Convert a stored organizationIdLegacy value to the array shape the current schema declares.\n * Accepts every physical shape a version 1 table can hold: a pipe-delimited string written by\n * 0.10.0 and earlier, a JSON array written by a fresh 0.10.1-next.4+ table, JSON array text left\n * by a partial hand fix, or an already-migrated array. Ids are trimmed, emptied entries are\n * dropped, duplicates are removed, and case is preserved because the values are DIDs.\n * @param value The stored value to convert.\n * @returns The de-duplicated list of ids, or undefined when there are none.\n */\nfunction toOrganizationIdList(value: unknown): string[] | undefined {\n\tlet parts: unknown[];\n\n\tif (Is.array(value)) {\n\t\tparts = value;\n\t} else if (Is.stringValue(value) && value.trim().startsWith(\"[\")) {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(value);\n\t\t\tparts = Is.array(parsed) ? parsed : [];\n\t\t} catch {\n\t\t\tparts = [];\n\t\t}\n\t} else if (Is.stringValue(value)) {\n\t\tparts = value.split(\"|\");\n\t} else {\n\t\tparts = [];\n\t}\n\n\tconst ids: string[] = [];\n\tfor (const part of parts) {\n\t\tconst id = Is.stringValue(part) ? part.trim() : \"\";\n\t\tif (id.length > 0 && !ids.includes(id)) {\n\t\t\tids.push(id);\n\t\t}\n\t}\n\n\treturn ids.length > 0 ? ids : undefined;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singleTenantProcessor.js","
|
|
1
|
+
{"version":3,"file":"singleTenantProcessor.js","sources":["../../src/singleTenantProcessor.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EACN,eAAe,EAKf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAoB,MAAM,iBAAiB,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C;;GAEG;AACH,MAAM,OAAO,qBAAqB;IACjC;;OAEG;IACI,MAAM,CAAU,UAAU,GAAW,uBAAuB,CAAC;IAEpE;;;OAGG;IACK,mBAAmB,CAAU;IAErC;;;OAGG;IACc,kBAAkB,CAAU;IAE7C;;;OAGG;IACH,YAAY,OAAkD;QAC7D,IAAI,CAAC,kBAAkB,GAAG,OAAO,EAAE,MAAM,EAAE,iBAAiB,IAAI,KAAK,CAAC;IACvE,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,qBAAqB,CAAC,UAAU,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,KAAK,CAAC,wBAAiC;QACnD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,eAAe,CAAC,KAAK,CAAC,UAAU,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,CAAC,mBAAmB,GAAG,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IACnE,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,GAAG,CACf,OAA2B,EAC3B,QAAuB,EACvB,KAA6B,EAC7B,UAAuB,EACvB,cAAyC;QAEzC,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC;QAElE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC;gBACJ,wGAAwG;gBACxG,wHAAwH;gBACxH,oEAAoE;gBACpE,MAAM,wBAAwB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;gBAC7E,IACC,EAAE,CAAC,WAAW,CAAC,wBAAwB,CAAC;oBACxC,wBAAwB,KAAK,IAAI,CAAC,mBAAmB,EACpD,CAAC;oBACF,MAAM,IAAI,iBAAiB,CAAC,qBAAqB,CAAC,UAAU,EAAE,uBAAuB,EAAE;wBACtF,SAAS,EAAE,aAAa,CAAC,YAAY;wBACrC,KAAK,EAAE,wBAAwB;qBAC/B,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,eAAe,CAAC,aAAa,CAC5B,QAAQ,EACR,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,EACxB,cAAc,CAAC,YAAY,EAC3B,IAAI,CAAC,kBAAkB,CACvB,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC;CACD","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\tHttpErrorHelper,\n\ttype IBaseRoute,\n\ttype IBaseRouteProcessor,\n\ttype IHttpResponse,\n\ttype IHttpServerRequest\n} from \"@3sixty/api-models\";\nimport { ContextIdHelper, ContextIdKeys, ContextIdStore, type IContextIds } from \"@3sixty/context\";\nimport { BaseError, Is, UnauthorizedError } from \"@3sixty/core\";\n\nimport { HttpStatusCode } from \"@3sixty/web\";\nimport type { ISingleTenantProcessorConstructorOptions } from \"./models/ISingleTenantProcessorConstructorOptions.js\";\n\n/**\n * Injects the single-tenant organization ID into every request context and validates any organization query parameter.\n */\nexport class SingleTenantProcessor implements IBaseRouteProcessor {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = \"SingleTenantProcessor\";\n\n\t/**\n\t * The organization ID for the single-tenant node, cached at startup.\n\t * @internal\n\t */\n\tprivate _nodeOrganizationId?: string;\n\n\t/**\n\t * Include the stack with errors.\n\t * @internal\n\t */\n\tprivate readonly _includeErrorStack: boolean;\n\n\t/**\n\t * Create a new instance of SingleTenantProcessor.\n\t * @param options Options for the processor.\n\t */\n\tconstructor(options?: ISingleTenantProcessorConstructorOptions) {\n\t\tthis._includeErrorStack = options?.config?.includeErrorStack ?? false;\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 SingleTenantProcessor.CLASS_NAME;\n\t}\n\n\t/**\n\t * Cache the node organization ID from the engine context so it can be injected into each\n\t * per-request context without requiring a separate ContextIdProcessor for Organization.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns A promise that resolves when the node organization ID has been cached.\n\t */\n\tpublic async start(nodeLoggingComponentType?: string): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tContextIdHelper.guard(contextIds, ContextIdKeys.Organization);\n\t\tthis._nodeOrganizationId = contextIds[ContextIdKeys.Organization];\n\t}\n\n\t/**\n\t * Pre process the REST request for the specified route.\n\t * @param request The incoming request.\n\t * @param response The outgoing response.\n\t * @param route The route to process.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t * @returns A promise that resolves when the organization ID has been injected and any query parameter validated.\n\t */\n\tpublic async pre(\n\t\trequest: IHttpServerRequest,\n\t\tresponse: IHttpResponse,\n\t\troute: IBaseRoute | undefined,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: { [id: string]: unknown }\n\t): Promise<void> {\n\t\tcontextIds[ContextIdKeys.Organization] = this._nodeOrganizationId;\n\n\t\tif (!Is.empty(route)) {\n\t\t\ttry {\n\t\t\t\t// If an organization ID is provided as a query parameter, validate it against the node organization ID.\n\t\t\t\t// since this processor is meant for single-tenant use cases, the presence of an organization ID is probably in the form\n\t\t\t\t// of a callback, so we should still validate it but not require it.\n\t\t\t\tconst organizationIdQueryParam = request.query?.[ContextIdKeys.Organization];\n\t\t\t\tif (\n\t\t\t\t\tIs.stringValue(organizationIdQueryParam) &&\n\t\t\t\t\torganizationIdQueryParam !== this._nodeOrganizationId\n\t\t\t\t) {\n\t\t\t\t\tthrow new UnauthorizedError(SingleTenantProcessor.CLASS_NAME, \"invalidOrganizationId\", {\n\t\t\t\t\t\tparamName: ContextIdKeys.Organization,\n\t\t\t\t\t\tvalue: organizationIdQueryParam\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tHttpErrorHelper.buildResponse(\n\t\t\t\t\tresponse,\n\t\t\t\t\tBaseError.fromError(err),\n\t\t\t\t\tHttpStatusCode.unauthorized,\n\t\t\t\t\tthis._includeErrorStack\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// Copyright 2026 3Sixty Trade Ltd.
|
|
2
3
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
-
import { HealthCategory, HealthStatus } from "@3sixty/api-models";
|
|
4
|
+
import { HealthCategory, HealthStatus, TenantEventType } from "@3sixty/api-models";
|
|
4
5
|
import { ContextIdKeys, ContextIdStore } from "@3sixty/context";
|
|
5
|
-
import { AlreadyExistsError, BaseError, Converter, GeneralError, Guards, Is, LfuCache, NotFoundError, Url } from "@3sixty/core";
|
|
6
|
+
import { AlreadyExistsError, BaseError, ComponentFactory, Converter, GeneralError, Guards, Is, LfuCache, NotFoundError, Url } from "@3sixty/core";
|
|
6
7
|
import { Blake2b } from "@3sixty/crypto";
|
|
7
8
|
import { ComparisonOperator } from "@3sixty/entity";
|
|
8
9
|
import { EntityStorageConnectorFactory } from "@3sixty/entity-storage-models";
|
|
@@ -46,6 +47,11 @@ export class TenantAdminService {
|
|
|
46
47
|
* @internal
|
|
47
48
|
*/
|
|
48
49
|
_entityStorageConnector;
|
|
50
|
+
/**
|
|
51
|
+
* Platform component used to fire tenant events.
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
_platformComponent;
|
|
49
55
|
/**
|
|
50
56
|
* The cache of tenant lookups, undefined when caching is disabled.
|
|
51
57
|
* @internal
|
|
@@ -62,6 +68,7 @@ export class TenantAdminService {
|
|
|
62
68
|
*/
|
|
63
69
|
constructor(options) {
|
|
64
70
|
this._entityStorageConnector = EntityStorageConnectorFactory.get(options?.tenantEntityStorageType ?? "tenant");
|
|
71
|
+
this._platformComponent = ComponentFactory.get(options?.platformComponentType ?? "platform");
|
|
65
72
|
this._tenantCacheTtlMs =
|
|
66
73
|
options?.config?.tenantCacheTtlMs ?? TenantAdminService._DEFAULT_CACHE_TTL_MS;
|
|
67
74
|
if (this._tenantCacheTtlMs > 0) {
|
|
@@ -217,6 +224,7 @@ export class TenantAdminService {
|
|
|
217
224
|
// tenant currently answers through its legacy list may already be cached against that
|
|
218
225
|
// tenant even though the new tenant now owns it outright.
|
|
219
226
|
this.invalidateTenant(tenantEntity);
|
|
227
|
+
await this._platformComponent.fireTenantEvent(tenantEntity.id, TenantEventType.Created);
|
|
220
228
|
return tenantEntity.id;
|
|
221
229
|
}
|
|
222
230
|
/**
|
|
@@ -289,6 +297,7 @@ export class TenantAdminService {
|
|
|
289
297
|
// cached under the previous values have to go as well as the new ones.
|
|
290
298
|
this.invalidateTenant(currentTenantEntity);
|
|
291
299
|
this.invalidateTenant(tenantEntity);
|
|
300
|
+
await this._platformComponent.fireTenantEvent(tenantEntity.id, TenantEventType.Updated);
|
|
292
301
|
}
|
|
293
302
|
/**
|
|
294
303
|
* Remove a tenant by its id.
|
|
@@ -311,6 +320,7 @@ export class TenantAdminService {
|
|
|
311
320
|
// under the id before it went missing still has to go.
|
|
312
321
|
this._tenantCache?.delete(`${TenantAdminService._CACHE_PREFIX_ID}${tenantId}`);
|
|
313
322
|
}
|
|
323
|
+
await this._platformComponent.fireTenantEvent(tenantId, TenantEventType.Deleted);
|
|
314
324
|
}
|
|
315
325
|
/**
|
|
316
326
|
* Query tenants with pagination.
|
|
@@ -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 {\n\ttype HealthApplicationCallback,\n\tHealthCategory,\n\tHealthStatus,\n\ttype IHealth,\n\ttype IHealthProviderComponent,\n\ttype ITenant,\n\ttype ITenantAdminComponent\n} from \"@3sixty/api-models\";\nimport { ContextIdKeys, ContextIdStore, type IContextIds } from \"@3sixty/context\";\nimport {\n\tAlreadyExistsError,\n\tBaseError,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\ttype IError,\n\tIs,\n\tLfuCache,\n\tNotFoundError,\n\tUrl\n} from \"@3sixty/core\";\nimport { Blake2b } from \"@3sixty/crypto\";\nimport { ComparisonOperator, type EntityCondition } from \"@3sixty/entity\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@3sixty/entity-storage-models\";\nimport { nameof } from \"@3sixty/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 tenant administration operations.\n */\nexport class TenantAdminService implements ITenantAdminComponent, IHealthProviderComponent {\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 * The default time to keep a tenant lookup in the cache.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_CACHE_TTL_MS: number = 30000;\n\n\t/**\n\t * The cache key prefix for tenants looked up by id.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_ID: string = \"id:\";\n\n\t/**\n\t * The cache key prefix for tenants looked up by api key.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_API_KEY: string = \"apiKey:\";\n\n\t/**\n\t * The cache key prefix for tenants looked up by public origin.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_PUBLIC_ORIGIN: string = \"publicOrigin:\";\n\n\t/**\n\t * The cache key prefix for tenants looked up by organization id, including legacy ids.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_ORGANIZATION_ID: string = \"organizationId:\";\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 * The cache of tenant lookups, undefined when caching is disabled.\n\t * @internal\n\t */\n\tprivate readonly _tenantCache?: LfuCache<ITenant>;\n\n\t/**\n\t * How long a cached tenant may live, counted from when it was read.\n\t * @internal\n\t */\n\tprivate readonly _tenantCacheTtlMs: number;\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\n\t\tthis._tenantCacheTtlMs =\n\t\t\toptions?.config?.tenantCacheTtlMs ?? TenantAdminService._DEFAULT_CACHE_TTL_MS;\n\t\tif (this._tenantCacheTtlMs > 0) {\n\t\t\tthis._tenantCache = new LfuCache<ITenant>({\n\t\t\t\tcapacity: options?.config?.tenantCacheCapacity,\n\t\t\t\tttiMs: this._tenantCacheTtlMs,\n\t\t\t\tmutexTimeoutMs: options?.config?.tenantCacheMutexTimeoutMs\n\t\t\t});\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 * Stop the service and release the tenant cache.\n\t * @returns A promise that resolves when the service has stopped.\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tthis._tenantCache?.destroy();\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\treturn this.cachedLookup(`${TenantAdminService._CACHE_PREFIX_ID}${tenantId}`, async () => {\n\t\t\tconst tenant = await this._entityStorageConnector.get(tenantId);\n\t\t\tif (!Is.object(tenant)) {\n\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", tenantId);\n\t\t\t}\n\n\t\t\treturn this.entityToModel(tenant);\n\t\t});\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\treturn this.cachedLookup(this.apiKeyCacheKey(apiKey), async () => {\n\t\t\tconst tenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\t\t\tif (!Is.object(tenant)) {\n\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", apiKey);\n\t\t\t}\n\n\t\t\treturn this.entityToModel(tenant);\n\t\t});\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\treturn this.cachedLookup(\n\t\t\t`${TenantAdminService._CACHE_PREFIX_PUBLIC_ORIGIN}${publicOrigin}`,\n\t\t\tasync () => {\n\t\t\t\tconst tenant = await this._entityStorageConnector.get(publicOrigin, \"publicOrigin\");\n\n\t\t\t\tif (!Is.object(tenant)) {\n\t\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", publicOrigin);\n\t\t\t\t}\n\n\t\t\t\treturn this.entityToModel(tenant);\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Get a tenant by its organization id, optionally searching legacy ids.\n\t * @param organizationId The organization id of the tenant.\n\t * @param includeLegacy Whether to also search the legacy organization id array.\n\t * @returns The tenant.\n\t * @throws Error if the tenant is not found.\n\t */\n\tpublic async getTenantByOrganizationId(\n\t\torganizationId: string,\n\t\tincludeLegacy?: boolean\n\t): Promise<ITenant> {\n\t\tGuards.stringValue(TenantAdminService.CLASS_NAME, nameof(organizationId), organizationId);\n\n\t\treturn this.cachedLookup(\n\t\t\tthis.organizationIdCacheKey(organizationId, includeLegacy ?? false),\n\t\t\tasync () => {\n\t\t\t\tlet tenant = await this._entityStorageConnector.get(organizationId, \"organizationId\");\n\n\t\t\t\tif (!Is.object(tenant) && (includeLegacy ?? false)) {\n\t\t\t\t\tconst result = await this._entityStorageConnector.query(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tproperty: \"organizationIdLegacy\",\n\t\t\t\t\t\t\tcomparison: ComparisonOperator.Includes,\n\t\t\t\t\t\t\tvalue: organizationId\n\t\t\t\t\t\t},\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t1\n\t\t\t\t\t);\n\t\t\t\t\ttenant = (result.entities as Tenant[])[0];\n\t\t\t\t}\n\n\t\t\t\tif (!Is.object(tenant)) {\n\t\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", organizationId);\n\t\t\t\t}\n\n\t\t\t\treturn this.entityToModel(tenant);\n\t\t\t}\n\t\t);\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\tGuards.stringValue(\n\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\tnameof(tenant.organizationId),\n\t\t\ttenant.organizationId\n\t\t);\n\t\tif (Is.stringValue(tenant.id)) {\n\t\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.id), tenant.id, 32);\n\t\t\tconst existing = await this._entityStorageConnector.get(tenant.id);\n\t\t\tif (Is.object(existing)) {\n\t\t\t\tthrow new AlreadyExistsError(\n\t\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\t\"tenantAlreadyExists\",\n\t\t\t\t\ttenant.id\n\t\t\t\t);\n\t\t\t}\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\tif (Is.stringValue(publicOrigin)) {\n\t\t\tconst existingPublicOrigin = await this._entityStorageConnector.get(\n\t\t\t\tpublicOrigin,\n\t\t\t\t\"publicOrigin\"\n\t\t\t);\n\t\t\tif (Is.object(existingPublicOrigin)) {\n\t\t\t\tthrow new AlreadyExistsError(\n\t\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\t\"publicOriginAlreadyExists\",\n\t\t\t\t\tpublicOrigin\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst existingOrgId = await this._entityStorageConnector.get(\n\t\t\ttenant.organizationId,\n\t\t\t\"organizationId\"\n\t\t);\n\t\tif (Is.object(existingOrgId)) {\n\t\t\tthrow new AlreadyExistsError(\n\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\"organizationIdAlreadyExists\",\n\t\t\t\ttenant.organizationId\n\t\t\t);\n\t\t}\n\n\t\tconst tenantEntity: ITenant = {\n\t\t\tid: tenant.id ?? TenantIdHelper.generateTenantId(),\n\t\t\tapiKey: tenant.apiKey ?? TenantIdHelper.generateApiKey(),\n\t\t\tdateCreated: new Date(Date.now()).toISOString(),\n\t\t\tdateModified: new Date(Date.now()).toISOString(),\n\t\t\tlabel: tenant.label,\n\t\t\tpublicOrigin,\n\t\t\torganizationId: tenant.organizationId,\n\t\t\torganizationIdLegacy: tenant.organizationIdLegacy\n\t\t};\n\n\t\tawait this._entityStorageConnector.set(this.modelToEntity(tenantEntity));\n\n\t\t// A new tenant cannot have a stale id, api key or public origin entry, because those are\n\t\t// unique-checked above and failed lookups are never cached. Its organization ids can be\n\t\t// stale though; only the primary organization index is checked, so an id that another\n\t\t// tenant currently answers through its legacy list may already be cached against that\n\t\t// tenant even though the new tenant now owns it outright.\n\t\tthis.invalidateTenant(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 A promise that resolves when the tenant has been updated.\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\tGuards.stringValue(\n\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\tnameof(tenant.organizationId),\n\t\t\ttenant.organizationId\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\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\tif (Is.stringValue(publicOrigin)) {\n\t\t\tconst existingPublicOrigin = await this._entityStorageConnector.get(\n\t\t\t\tpublicOrigin,\n\t\t\t\t\"publicOrigin\"\n\t\t\t);\n\t\t\tif (Is.object(existingPublicOrigin) && existingPublicOrigin.id !== currentTenant.id) {\n\t\t\t\tthrow new AlreadyExistsError(\n\t\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\t\"publicOriginAlreadyExists\",\n\t\t\t\t\tpublicOrigin\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst existingOrgId = await this._entityStorageConnector.get(\n\t\t\ttenant.organizationId,\n\t\t\t\"organizationId\"\n\t\t);\n\t\tif (Is.object(existingOrgId) && existingOrgId.id !== currentTenant.id) {\n\t\t\tthrow new AlreadyExistsError(\n\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\"organizationIdAlreadyExists\",\n\t\t\t\ttenant.organizationId\n\t\t\t);\n\t\t}\n\n\t\tconst currentTenantEntity = this.entityToModel(currentTenant);\n\n\t\tconst orgIdChanged = tenant.organizationId !== currentTenantEntity.organizationId;\n\n\t\tlet newOrganizationIdLegacy: string[] | undefined;\n\t\tif (orgIdChanged) {\n\t\t\tconst legacySet = new Set(currentTenantEntity.organizationIdLegacy ?? []);\n\t\t\tif (Is.stringValue(currentTenantEntity.organizationId)) {\n\t\t\t\tlegacySet.add(currentTenantEntity.organizationId);\n\t\t\t}\n\t\t\tlegacySet.delete(tenant.organizationId);\n\t\t\tnewOrganizationIdLegacy = legacySet.size > 0 ? [...legacySet] : undefined;\n\t\t} else {\n\t\t\tnewOrganizationIdLegacy = Is.array(tenant.organizationIdLegacy)\n\t\t\t\t? tenant.organizationIdLegacy\n\t\t\t\t: currentTenantEntity.organizationIdLegacy;\n\t\t}\n\n\t\tconst tenantEntity: ITenant = {\n\t\t\tid: tenant.id,\n\t\t\tapiKey: tenant.apiKey ?? currentTenantEntity.apiKey,\n\t\t\tdateCreated: currentTenantEntity.dateCreated,\n\t\t\tdateModified: new Date(Date.now()).toISOString(),\n\t\t\tlabel: tenant.label ?? currentTenantEntity.label,\n\t\t\tpublicOrigin: publicOrigin ?? currentTenantEntity.publicOrigin,\n\t\t\torganizationId: tenant.organizationId,\n\t\t\torganizationIdLegacy: newOrganizationIdLegacy\n\t\t};\n\n\t\tawait this._entityStorageConnector.set(this.modelToEntity(tenantEntity));\n\n\t\t// The api key, organization id and public origin can all have moved, so the entries\n\t\t// cached under the previous values have to go as well as the new ones.\n\t\tthis.invalidateTenant(currentTenantEntity);\n\t\tthis.invalidateTenant(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\t// The keys to drop have to be read before the tenant goes, but the drop itself has to happen\n\t\t// after it, otherwise a lookup racing the delete would re-cache the tenant behind us.\n\t\tconst currentTenant = Is.empty(this._tenantCache)\n\t\t\t? undefined\n\t\t\t: await this._entityStorageConnector.get(tenantId);\n\n\t\tawait this._entityStorageConnector.remove(tenantId);\n\n\t\tif (Is.object(currentTenant)) {\n\t\t\tthis.invalidateTenant(this.entityToModel(currentTenant));\n\t\t} else {\n\t\t\t// The tenant could not be read back, so its other keys are unknown, but an entry cached\n\t\t\t// under the id before it went missing still has to go.\n\t\t\tthis._tenantCache?.delete(`${TenantAdminService._CACHE_PREFIX_ID}${tenantId}`);\n\t\t}\n\t}\n\n\t/**\n\t * Query tenants with pagination.\n\t * @param conditions The conditions to filter the tenants.\n\t * @param properties The properties to include in the returned 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\tconditions?: EntityCondition<ITenant>,\n\t\tproperties?: (keyof ITenant)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ tenants: ITenant[]; cursor?: string }> {\n\t\tconst result = await this._entityStorageConnector.query(\n\t\t\tconditions,\n\t\t\tundefined,\n\t\t\tproperties,\n\t\t\tcursor,\n\t\t\tlimit\n\t\t);\n\n\t\treturn {\n\t\t\ttenants: (result.entities as Tenant[]).map(e => this.entityToModel(e)),\n\t\t\tcursor: result.cursor\n\t\t};\n\t}\n\n\t/**\n\t * Provision a temporary tenant for the application health cycle.\n\t * @param contextIds Accumulated context IDs; receives the provisional tenant ID.\n\t * @returns A promise that resolves when provisioning is complete.\n\t */\n\tpublic async healthApplicationInit(contextIds: IContextIds): Promise<void> {\n\t\tconst organizationId = contextIds[ContextIdKeys.Organization];\n\t\tif (!Is.stringValue(organizationId)) {\n\t\t\treturn;\n\t\t}\n\t\tconst tenantId = await this.create({\n\t\t\tapiKey: TenantIdHelper.generateApiKey(),\n\t\t\torganizationId,\n\t\t\tlabel: \"health-check\"\n\t\t});\n\t\tcontextIds[ContextIdKeys.Tenant] = tenantId;\n\t}\n\n\t/**\n\t * Verify the provisioned tenant can be retrieved.\n\t * The tenant ID is read from the active context set by the init pass.\n\t * @param callback The callback to invoke when a deferred health result is ready.\n\t * @returns The health entries for this component.\n\t */\n\tpublic async healthApplication(\n\t\tcallback: HealthApplicationCallback\n\t): Promise<IHealth[] | undefined> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst tenantId = contextIds?.[ContextIdKeys.Tenant];\n\n\t\tif (!Is.stringValue(tenantId)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tlet status: HealthStatus = HealthStatus.Ok;\n\t\tlet healthError: IError | undefined;\n\n\t\ttry {\n\t\t\tawait this.get(tenantId);\n\t\t} catch (err) {\n\t\t\tstatus = HealthStatus.Error;\n\t\t\thealthError = BaseError.fromError(err);\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tsource: TenantAdminService.CLASS_NAME,\n\t\t\t\tcategory: HealthCategory.Application,\n\t\t\t\tstatus,\n\t\t\t\terror: healthError\n\t\t\t}\n\t\t];\n\t}\n\n\t/**\n\t * Remove the temporary tenant provisioned during init.\n\t * The tenant ID is read from the active context set by the init pass.\n\t * Does nothing when no tenant ID is present.\n\t * @returns A promise that resolves when teardown is complete.\n\t */\n\tpublic async healthApplicationTeardown(): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst tenantId = contextIds?.[ContextIdKeys.Tenant];\n\n\t\tif (Is.stringValue(tenantId)) {\n\t\t\tawait this.remove(tenantId);\n\t\t}\n\t}\n\n\t/**\n\t * Build the cache key used for an api key lookup.\n\t * The api key is hashed so neither the cache keys nor the mutex keys derived from them hold\n\t * the credential itself.\n\t * @param apiKey The api key being looked up.\n\t * @returns The cache key.\n\t * @internal\n\t */\n\tprivate apiKeyCacheKey(apiKey: string): string {\n\t\tconst hashed = Converter.bytesToHex(Blake2b.sum256(Converter.utf8ToBytes(apiKey)));\n\t\treturn `${TenantAdminService._CACHE_PREFIX_API_KEY}${hashed}`;\n\t}\n\n\t/**\n\t * Build the cache key used for an organization id lookup.\n\t * @param organizationId The organization id being looked up.\n\t * @param includeLegacy Whether the lookup also searches the legacy organization ids.\n\t * @returns The cache key.\n\t * @internal\n\t */\n\tprivate organizationIdCacheKey(organizationId: string, includeLegacy: boolean): string {\n\t\treturn `${TenantAdminService._CACHE_PREFIX_ORGANIZATION_ID}${includeLegacy ? \"legacy:\" : \"\"}${organizationId}`;\n\t}\n\n\t/**\n\t * Perform a lookup through the cache, falling back to a direct lookup when caching is disabled.\n\t * Lookups that throw are not cached, so a missing tenant is re-checked against storage each time.\n\t * @param cacheKey The key the tenant is cached under.\n\t * @param lookup The lookup to perform when the tenant is not already cached.\n\t * @returns The tenant.\n\t * @internal\n\t */\n\tprivate async cachedLookup(cacheKey: string, lookup: () => Promise<ITenant>): Promise<ITenant> {\n\t\tif (Is.empty(this._tenantCache)) {\n\t\t\treturn lookup();\n\t\t}\n\n\t\t// The expiry is absolute rather than the idle time the cache applies alongside it. Entries\n\t\t// are only invalidated in the process that made the change, so without it a tenant under\n\t\t// steady traffic on one node would never pick up an edit made on another.\n\t\tconst cached = await this._tenantCache.getOrSet(\n\t\t\tcacheKey,\n\t\t\tlookup,\n\t\t\tDate.now() + this._tenantCacheTtlMs\n\t\t);\n\n\t\t// Callers get their own copy; the cached instance is shared by every caller and some of\n\t\t// them fill in defaults on the tenant they are handed.\n\t\treturn {\n\t\t\t...cached,\n\t\t\torganizationIdLegacy: Is.array(cached.organizationIdLegacy)\n\t\t\t\t? [...cached.organizationIdLegacy]\n\t\t\t\t: undefined\n\t\t};\n\t}\n\n\t/**\n\t * Remove every cache entry that can resolve to the given tenant.\n\t * @param tenant The tenant whose cache entries should be dropped.\n\t * @internal\n\t */\n\tprivate invalidateTenant(tenant: ITenant): void {\n\t\tif (Is.empty(this._tenantCache)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._tenantCache.delete(`${TenantAdminService._CACHE_PREFIX_ID}${tenant.id}`);\n\n\t\tif (Is.stringValue(tenant.apiKey)) {\n\t\t\tthis._tenantCache.delete(this.apiKeyCacheKey(tenant.apiKey));\n\t\t}\n\n\t\tif (Is.stringValue(tenant.publicOrigin)) {\n\t\t\tthis._tenantCache.delete(\n\t\t\t\t`${TenantAdminService._CACHE_PREFIX_PUBLIC_ORIGIN}${tenant.publicOrigin}`\n\t\t\t);\n\t\t}\n\n\t\tconst organizationIds = [tenant.organizationId, ...(tenant.organizationIdLegacy ?? [])];\n\t\tfor (const organizationId of organizationIds) {\n\t\t\tif (Is.stringValue(organizationId)) {\n\t\t\t\tthis._tenantCache.delete(this.organizationIdCacheKey(organizationId, false));\n\t\t\t\tthis._tenantCache.delete(this.organizationIdCacheKey(organizationId, true));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Convert a tenant entity to a tenant model.\n\t * @param tenant The tenant entity.\n\t * @returns The tenant model.\n\t * @internal\n\t */\n\tprivate entityToModel(tenant: Tenant): ITenant {\n\t\treturn {\n\t\t\tid: tenant.id,\n\t\t\tapiKey: tenant.apiKey,\n\t\t\tlabel: tenant.label,\n\t\t\tdateCreated: tenant.dateCreated,\n\t\t\tdateModified: tenant.dateModified,\n\t\t\tpublicOrigin: tenant.publicOrigin,\n\t\t\torganizationId: tenant.organizationId,\n\t\t\torganizationIdLegacy: tenant.organizationIdLegacy\n\t\t};\n\t}\n\n\t/**\n\t * Convert a tenant model to a tenant entity.\n\t * @param tenant The tenant model.\n\t * @returns The tenant entity.\n\t * @internal\n\t */\n\tprivate modelToEntity(tenant: ITenant): Tenant {\n\t\tconst tenantEntity = new Tenant();\n\t\ttenantEntity.id = tenant.id;\n\t\ttenantEntity.apiKey = tenant.apiKey;\n\t\ttenantEntity.label = tenant.label;\n\t\ttenantEntity.dateCreated = tenant.dateCreated;\n\t\ttenantEntity.dateModified = tenant.dateModified;\n\t\ttenantEntity.publicOrigin = tenant.publicOrigin;\n\t\ttenantEntity.organizationId = tenant.organizationId;\n\t\ttenantEntity.organizationIdLegacy = Is.arrayValue(tenant.organizationIdLegacy)\n\t\t\t? tenant.organizationIdLegacy\n\t\t\t: undefined;\n\t\treturn tenantEntity;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tenantAdminService.js","sources":["../../src/tenantAdminService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// Copyright 2026 3Sixty Trade Ltd.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\ttype HealthApplicationCallback,\n\tHealthCategory,\n\tHealthStatus,\n\ttype IHealth,\n\ttype IHealthProviderComponent,\n\ttype IPlatformComponent,\n\ttype ITenant,\n\ttype ITenantAdminComponent,\n\tTenantEventType\n} from \"@3sixty/api-models\";\nimport { ContextIdKeys, ContextIdStore, type IContextIds } from \"@3sixty/context\";\nimport {\n\tAlreadyExistsError,\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\ttype IError,\n\tIs,\n\tLfuCache,\n\tNotFoundError,\n\tUrl\n} from \"@3sixty/core\";\nimport { Blake2b } from \"@3sixty/crypto\";\nimport { ComparisonOperator, type EntityCondition } from \"@3sixty/entity\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@3sixty/entity-storage-models\";\n\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 tenant administration operations.\n */\nexport class TenantAdminService implements ITenantAdminComponent, IHealthProviderComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = \"TenantAdminService\";\n\n\t/**\n\t * The default time to keep a tenant lookup in the cache.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_CACHE_TTL_MS: number = 30000;\n\n\t/**\n\t * The cache key prefix for tenants looked up by id.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_ID: string = \"id:\";\n\n\t/**\n\t * The cache key prefix for tenants looked up by api key.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_API_KEY: string = \"apiKey:\";\n\n\t/**\n\t * The cache key prefix for tenants looked up by public origin.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_PUBLIC_ORIGIN: string = \"publicOrigin:\";\n\n\t/**\n\t * The cache key prefix for tenants looked up by organization id, including legacy ids.\n\t * @internal\n\t */\n\tprivate static readonly _CACHE_PREFIX_ORGANIZATION_ID: string = \"organizationId:\";\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 * Platform component used to fire tenant events.\n\t * @internal\n\t */\n\tprivate readonly _platformComponent: IPlatformComponent;\n\n\t/**\n\t * The cache of tenant lookups, undefined when caching is disabled.\n\t * @internal\n\t */\n\tprivate readonly _tenantCache?: LfuCache<ITenant>;\n\n\t/**\n\t * How long a cached tenant may live, counted from when it was read.\n\t * @internal\n\t */\n\tprivate readonly _tenantCacheTtlMs: number;\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\tthis._platformComponent = ComponentFactory.get<IPlatformComponent>(\n\t\t\toptions?.platformComponentType ?? \"platform\"\n\t\t);\n\n\t\tthis._tenantCacheTtlMs =\n\t\t\toptions?.config?.tenantCacheTtlMs ?? TenantAdminService._DEFAULT_CACHE_TTL_MS;\n\t\tif (this._tenantCacheTtlMs > 0) {\n\t\t\tthis._tenantCache = new LfuCache<ITenant>({\n\t\t\t\tcapacity: options?.config?.tenantCacheCapacity,\n\t\t\t\tttiMs: this._tenantCacheTtlMs,\n\t\t\t\tmutexTimeoutMs: options?.config?.tenantCacheMutexTimeoutMs\n\t\t\t});\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 * Stop the service and release the tenant cache.\n\t * @returns A promise that resolves when the service has stopped.\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tthis._tenantCache?.destroy();\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, \"tenantId\", tenantId, 32);\n\n\t\treturn this.cachedLookup(`${TenantAdminService._CACHE_PREFIX_ID}${tenantId}`, async () => {\n\t\t\tconst tenant = await this._entityStorageConnector.get(tenantId);\n\t\t\tif (!Is.object(tenant)) {\n\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", tenantId);\n\t\t\t}\n\n\t\t\treturn this.entityToModel(tenant);\n\t\t});\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, \"apiKey\", apiKey, 32);\n\n\t\treturn this.cachedLookup(this.apiKeyCacheKey(apiKey), async () => {\n\t\t\tconst tenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\t\t\tif (!Is.object(tenant)) {\n\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", apiKey);\n\t\t\t}\n\n\t\t\treturn this.entityToModel(tenant);\n\t\t});\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, \"publicOrigin\", publicOrigin);\n\n\t\treturn this.cachedLookup(\n\t\t\t`${TenantAdminService._CACHE_PREFIX_PUBLIC_ORIGIN}${publicOrigin}`,\n\t\t\tasync () => {\n\t\t\t\tconst tenant = await this._entityStorageConnector.get(publicOrigin, \"publicOrigin\");\n\n\t\t\t\tif (!Is.object(tenant)) {\n\t\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", publicOrigin);\n\t\t\t\t}\n\n\t\t\t\treturn this.entityToModel(tenant);\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Get a tenant by its organization id, optionally searching legacy ids.\n\t * @param organizationId The organization id of the tenant.\n\t * @param includeLegacy Whether to also search the legacy organization id array.\n\t * @returns The tenant.\n\t * @throws Error if the tenant is not found.\n\t */\n\tpublic async getTenantByOrganizationId(\n\t\torganizationId: string,\n\t\tincludeLegacy?: boolean\n\t): Promise<ITenant> {\n\t\tGuards.stringValue(TenantAdminService.CLASS_NAME, \"organizationId\", organizationId);\n\n\t\treturn this.cachedLookup(\n\t\t\tthis.organizationIdCacheKey(organizationId, includeLegacy ?? false),\n\t\t\tasync () => {\n\t\t\t\tlet tenant = await this._entityStorageConnector.get(organizationId, \"organizationId\");\n\n\t\t\t\tif (!Is.object(tenant) && (includeLegacy ?? false)) {\n\t\t\t\t\tconst result = await this._entityStorageConnector.query(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tproperty: \"organizationIdLegacy\",\n\t\t\t\t\t\t\tcomparison: ComparisonOperator.Includes,\n\t\t\t\t\t\t\tvalue: organizationId\n\t\t\t\t\t\t},\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t1\n\t\t\t\t\t);\n\t\t\t\t\ttenant = (result.entities as Tenant[])[0];\n\t\t\t\t}\n\n\t\t\t\tif (!Is.object(tenant)) {\n\t\t\t\t\tthrow new NotFoundError(TenantAdminService.CLASS_NAME, \"tenantNotFound\", organizationId);\n\t\t\t\t}\n\n\t\t\t\treturn this.entityToModel(tenant);\n\t\t\t}\n\t\t);\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, \"tenant\", tenant);\n\t\tGuards.stringValue(\n\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\"tenant.organizationId\",\n\t\t\ttenant.organizationId\n\t\t);\n\t\tif (Is.stringValue(tenant.id)) {\n\t\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, \"tenant.id\", tenant.id, 32);\n\t\t\tconst existing = await this._entityStorageConnector.get(tenant.id);\n\t\t\tif (Is.object(existing)) {\n\t\t\t\tthrow new AlreadyExistsError(\n\t\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\t\"tenantAlreadyExists\",\n\t\t\t\t\ttenant.id\n\t\t\t\t);\n\t\t\t}\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\t\"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, \"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\tif (Is.stringValue(publicOrigin)) {\n\t\t\tconst existingPublicOrigin = await this._entityStorageConnector.get(\n\t\t\t\tpublicOrigin,\n\t\t\t\t\"publicOrigin\"\n\t\t\t);\n\t\t\tif (Is.object(existingPublicOrigin)) {\n\t\t\t\tthrow new AlreadyExistsError(\n\t\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\t\"publicOriginAlreadyExists\",\n\t\t\t\t\tpublicOrigin\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst existingOrgId = await this._entityStorageConnector.get(\n\t\t\ttenant.organizationId,\n\t\t\t\"organizationId\"\n\t\t);\n\t\tif (Is.object(existingOrgId)) {\n\t\t\tthrow new AlreadyExistsError(\n\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\"organizationIdAlreadyExists\",\n\t\t\t\ttenant.organizationId\n\t\t\t);\n\t\t}\n\n\t\tconst tenantEntity: ITenant = {\n\t\t\tid: tenant.id ?? TenantIdHelper.generateTenantId(),\n\t\t\tapiKey: tenant.apiKey ?? TenantIdHelper.generateApiKey(),\n\t\t\tdateCreated: new Date(Date.now()).toISOString(),\n\t\t\tdateModified: new Date(Date.now()).toISOString(),\n\t\t\tlabel: tenant.label,\n\t\t\tpublicOrigin,\n\t\t\torganizationId: tenant.organizationId,\n\t\t\torganizationIdLegacy: tenant.organizationIdLegacy\n\t\t};\n\n\t\tawait this._entityStorageConnector.set(this.modelToEntity(tenantEntity));\n\n\t\t// A new tenant cannot have a stale id, api key or public origin entry, because those are\n\t\t// unique-checked above and failed lookups are never cached. Its organization ids can be\n\t\t// stale though; only the primary organization index is checked, so an id that another\n\t\t// tenant currently answers through its legacy list may already be cached against that\n\t\t// tenant even though the new tenant now owns it outright.\n\t\tthis.invalidateTenant(tenantEntity);\n\n\t\tawait this._platformComponent.fireTenantEvent(tenantEntity.id, TenantEventType.Created);\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 A promise that resolves when the tenant has been updated.\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, \"tenant\", tenant);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, \"tenant.id\", tenant.id, 32);\n\t\tGuards.stringValue(\n\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\"tenant.organizationId\",\n\t\t\ttenant.organizationId\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\t\"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, \"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\tif (Is.stringValue(publicOrigin)) {\n\t\t\tconst existingPublicOrigin = await this._entityStorageConnector.get(\n\t\t\t\tpublicOrigin,\n\t\t\t\t\"publicOrigin\"\n\t\t\t);\n\t\t\tif (Is.object(existingPublicOrigin) && existingPublicOrigin.id !== currentTenant.id) {\n\t\t\t\tthrow new AlreadyExistsError(\n\t\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\t\"publicOriginAlreadyExists\",\n\t\t\t\t\tpublicOrigin\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst existingOrgId = await this._entityStorageConnector.get(\n\t\t\ttenant.organizationId,\n\t\t\t\"organizationId\"\n\t\t);\n\t\tif (Is.object(existingOrgId) && existingOrgId.id !== currentTenant.id) {\n\t\t\tthrow new AlreadyExistsError(\n\t\t\t\tTenantAdminService.CLASS_NAME,\n\t\t\t\t\"organizationIdAlreadyExists\",\n\t\t\t\ttenant.organizationId\n\t\t\t);\n\t\t}\n\n\t\tconst currentTenantEntity = this.entityToModel(currentTenant);\n\n\t\tconst orgIdChanged = tenant.organizationId !== currentTenantEntity.organizationId;\n\n\t\tlet newOrganizationIdLegacy: string[] | undefined;\n\t\tif (orgIdChanged) {\n\t\t\tconst legacySet = new Set(currentTenantEntity.organizationIdLegacy ?? []);\n\t\t\tif (Is.stringValue(currentTenantEntity.organizationId)) {\n\t\t\t\tlegacySet.add(currentTenantEntity.organizationId);\n\t\t\t}\n\t\t\tlegacySet.delete(tenant.organizationId);\n\t\t\tnewOrganizationIdLegacy = legacySet.size > 0 ? [...legacySet] : undefined;\n\t\t} else {\n\t\t\tnewOrganizationIdLegacy = Is.array(tenant.organizationIdLegacy)\n\t\t\t\t? tenant.organizationIdLegacy\n\t\t\t\t: currentTenantEntity.organizationIdLegacy;\n\t\t}\n\n\t\tconst tenantEntity: ITenant = {\n\t\t\tid: tenant.id,\n\t\t\tapiKey: tenant.apiKey ?? currentTenantEntity.apiKey,\n\t\t\tdateCreated: currentTenantEntity.dateCreated,\n\t\t\tdateModified: new Date(Date.now()).toISOString(),\n\t\t\tlabel: tenant.label ?? currentTenantEntity.label,\n\t\t\tpublicOrigin: publicOrigin ?? currentTenantEntity.publicOrigin,\n\t\t\torganizationId: tenant.organizationId,\n\t\t\torganizationIdLegacy: newOrganizationIdLegacy\n\t\t};\n\n\t\tawait this._entityStorageConnector.set(this.modelToEntity(tenantEntity));\n\n\t\t// The api key, organization id and public origin can all have moved, so the entries\n\t\t// cached under the previous values have to go as well as the new ones.\n\t\tthis.invalidateTenant(currentTenantEntity);\n\t\tthis.invalidateTenant(tenantEntity);\n\n\t\tawait this._platformComponent.fireTenantEvent(tenantEntity.id, TenantEventType.Updated);\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, \"tenantId\", tenantId, 32);\n\n\t\t// The keys to drop have to be read before the tenant goes, but the drop itself has to happen\n\t\t// after it, otherwise a lookup racing the delete would re-cache the tenant behind us.\n\t\tconst currentTenant = Is.empty(this._tenantCache)\n\t\t\t? undefined\n\t\t\t: await this._entityStorageConnector.get(tenantId);\n\n\t\tawait this._entityStorageConnector.remove(tenantId);\n\n\t\tif (Is.object(currentTenant)) {\n\t\t\tthis.invalidateTenant(this.entityToModel(currentTenant));\n\t\t} else {\n\t\t\t// The tenant could not be read back, so its other keys are unknown, but an entry cached\n\t\t\t// under the id before it went missing still has to go.\n\t\t\tthis._tenantCache?.delete(`${TenantAdminService._CACHE_PREFIX_ID}${tenantId}`);\n\t\t}\n\n\t\tawait this._platformComponent.fireTenantEvent(tenantId, TenantEventType.Deleted);\n\t}\n\n\t/**\n\t * Query tenants with pagination.\n\t * @param conditions The conditions to filter the tenants.\n\t * @param properties The properties to include in the returned 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\tconditions?: EntityCondition<ITenant>,\n\t\tproperties?: (keyof ITenant)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ tenants: ITenant[]; cursor?: string }> {\n\t\tconst result = await this._entityStorageConnector.query(\n\t\t\tconditions,\n\t\t\tundefined,\n\t\t\tproperties,\n\t\t\tcursor,\n\t\t\tlimit\n\t\t);\n\n\t\treturn {\n\t\t\ttenants: (result.entities as Tenant[]).map(e => this.entityToModel(e)),\n\t\t\tcursor: result.cursor\n\t\t};\n\t}\n\n\t/**\n\t * Provision a temporary tenant for the application health cycle.\n\t * @param contextIds Accumulated context IDs; receives the provisional tenant ID.\n\t * @returns A promise that resolves when provisioning is complete.\n\t */\n\tpublic async healthApplicationInit(contextIds: IContextIds): Promise<void> {\n\t\tconst organizationId = contextIds[ContextIdKeys.Organization];\n\t\tif (!Is.stringValue(organizationId)) {\n\t\t\treturn;\n\t\t}\n\t\tconst tenantId = await this.create({\n\t\t\tapiKey: TenantIdHelper.generateApiKey(),\n\t\t\torganizationId,\n\t\t\tlabel: \"health-check\"\n\t\t});\n\t\tcontextIds[ContextIdKeys.Tenant] = tenantId;\n\t}\n\n\t/**\n\t * Verify the provisioned tenant can be retrieved.\n\t * The tenant ID is read from the active context set by the init pass.\n\t * @param callback The callback to invoke when a deferred health result is ready.\n\t * @returns The health entries for this component.\n\t */\n\tpublic async healthApplication(\n\t\tcallback: HealthApplicationCallback\n\t): Promise<IHealth[] | undefined> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst tenantId = contextIds?.[ContextIdKeys.Tenant];\n\n\t\tif (!Is.stringValue(tenantId)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tlet status: HealthStatus = HealthStatus.Ok;\n\t\tlet healthError: IError | undefined;\n\n\t\ttry {\n\t\t\tawait this.get(tenantId);\n\t\t} catch (err) {\n\t\t\tstatus = HealthStatus.Error;\n\t\t\thealthError = BaseError.fromError(err);\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tsource: TenantAdminService.CLASS_NAME,\n\t\t\t\tcategory: HealthCategory.Application,\n\t\t\t\tstatus,\n\t\t\t\terror: healthError\n\t\t\t}\n\t\t];\n\t}\n\n\t/**\n\t * Remove the temporary tenant provisioned during init.\n\t * The tenant ID is read from the active context set by the init pass.\n\t * Does nothing when no tenant ID is present.\n\t * @returns A promise that resolves when teardown is complete.\n\t */\n\tpublic async healthApplicationTeardown(): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst tenantId = contextIds?.[ContextIdKeys.Tenant];\n\n\t\tif (Is.stringValue(tenantId)) {\n\t\t\tawait this.remove(tenantId);\n\t\t}\n\t}\n\n\t/**\n\t * Build the cache key used for an api key lookup.\n\t * The api key is hashed so neither the cache keys nor the mutex keys derived from them hold\n\t * the credential itself.\n\t * @param apiKey The api key being looked up.\n\t * @returns The cache key.\n\t * @internal\n\t */\n\tprivate apiKeyCacheKey(apiKey: string): string {\n\t\tconst hashed = Converter.bytesToHex(Blake2b.sum256(Converter.utf8ToBytes(apiKey)));\n\t\treturn `${TenantAdminService._CACHE_PREFIX_API_KEY}${hashed}`;\n\t}\n\n\t/**\n\t * Build the cache key used for an organization id lookup.\n\t * @param organizationId The organization id being looked up.\n\t * @param includeLegacy Whether the lookup also searches the legacy organization ids.\n\t * @returns The cache key.\n\t * @internal\n\t */\n\tprivate organizationIdCacheKey(organizationId: string, includeLegacy: boolean): string {\n\t\treturn `${TenantAdminService._CACHE_PREFIX_ORGANIZATION_ID}${includeLegacy ? \"legacy:\" : \"\"}${organizationId}`;\n\t}\n\n\t/**\n\t * Perform a lookup through the cache, falling back to a direct lookup when caching is disabled.\n\t * Lookups that throw are not cached, so a missing tenant is re-checked against storage each time.\n\t * @param cacheKey The key the tenant is cached under.\n\t * @param lookup The lookup to perform when the tenant is not already cached.\n\t * @returns The tenant.\n\t * @internal\n\t */\n\tprivate async cachedLookup(cacheKey: string, lookup: () => Promise<ITenant>): Promise<ITenant> {\n\t\tif (Is.empty(this._tenantCache)) {\n\t\t\treturn lookup();\n\t\t}\n\n\t\t// The expiry is absolute rather than the idle time the cache applies alongside it. Entries\n\t\t// are only invalidated in the process that made the change, so without it a tenant under\n\t\t// steady traffic on one node would never pick up an edit made on another.\n\t\tconst cached = await this._tenantCache.getOrSet(\n\t\t\tcacheKey,\n\t\t\tlookup,\n\t\t\tDate.now() + this._tenantCacheTtlMs\n\t\t);\n\n\t\t// Callers get their own copy; the cached instance is shared by every caller and some of\n\t\t// them fill in defaults on the tenant they are handed.\n\t\treturn {\n\t\t\t...cached,\n\t\t\torganizationIdLegacy: Is.array(cached.organizationIdLegacy)\n\t\t\t\t? [...cached.organizationIdLegacy]\n\t\t\t\t: undefined\n\t\t};\n\t}\n\n\t/**\n\t * Remove every cache entry that can resolve to the given tenant.\n\t * @param tenant The tenant whose cache entries should be dropped.\n\t * @internal\n\t */\n\tprivate invalidateTenant(tenant: ITenant): void {\n\t\tif (Is.empty(this._tenantCache)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._tenantCache.delete(`${TenantAdminService._CACHE_PREFIX_ID}${tenant.id}`);\n\n\t\tif (Is.stringValue(tenant.apiKey)) {\n\t\t\tthis._tenantCache.delete(this.apiKeyCacheKey(tenant.apiKey));\n\t\t}\n\n\t\tif (Is.stringValue(tenant.publicOrigin)) {\n\t\t\tthis._tenantCache.delete(\n\t\t\t\t`${TenantAdminService._CACHE_PREFIX_PUBLIC_ORIGIN}${tenant.publicOrigin}`\n\t\t\t);\n\t\t}\n\n\t\tconst organizationIds = [tenant.organizationId, ...(tenant.organizationIdLegacy ?? [])];\n\t\tfor (const organizationId of organizationIds) {\n\t\t\tif (Is.stringValue(organizationId)) {\n\t\t\t\tthis._tenantCache.delete(this.organizationIdCacheKey(organizationId, false));\n\t\t\t\tthis._tenantCache.delete(this.organizationIdCacheKey(organizationId, true));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Convert a tenant entity to a tenant model.\n\t * @param tenant The tenant entity.\n\t * @returns The tenant model.\n\t * @internal\n\t */\n\tprivate entityToModel(tenant: Tenant): ITenant {\n\t\treturn {\n\t\t\tid: tenant.id,\n\t\t\tapiKey: tenant.apiKey,\n\t\t\tlabel: tenant.label,\n\t\t\tdateCreated: tenant.dateCreated,\n\t\t\tdateModified: tenant.dateModified,\n\t\t\tpublicOrigin: tenant.publicOrigin,\n\t\t\torganizationId: tenant.organizationId,\n\t\t\torganizationIdLegacy: tenant.organizationIdLegacy\n\t\t};\n\t}\n\n\t/**\n\t * Convert a tenant model to a tenant entity.\n\t * @param tenant The tenant model.\n\t * @returns The tenant entity.\n\t * @internal\n\t */\n\tprivate modelToEntity(tenant: ITenant): Tenant {\n\t\tconst tenantEntity = new Tenant();\n\t\ttenantEntity.id = tenant.id;\n\t\ttenantEntity.apiKey = tenant.apiKey;\n\t\ttenantEntity.label = tenant.label;\n\t\ttenantEntity.dateCreated = tenant.dateCreated;\n\t\ttenantEntity.dateModified = tenant.dateModified;\n\t\ttenantEntity.publicOrigin = tenant.publicOrigin;\n\t\ttenantEntity.organizationId = tenant.organizationId;\n\t\ttenantEntity.organizationIdLegacy = Is.arrayValue(tenant.organizationIdLegacy)\n\t\t\t? tenant.organizationIdLegacy\n\t\t\t: undefined;\n\t\treturn tenantEntity;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenantIdContextIdHandler.js","
|
|
1
|
+
{"version":3,"file":"tenantIdContextIdHandler.js","sources":["../../src/tenantIdContextIdHandler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAGrD;;GAEG;AACH,MAAM,OAAO,wBAAwB;IACpC;;OAEG;IACI,MAAM,CAAU,UAAU,GAAW,0BAA0B,CAAC;IAEvE;;;OAGG;IACI,SAAS;QACf,OAAO,wBAAwB,CAAC,UAAU,CAAC;IAC5C,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,KAAa;QACzB,OAAO,SAAS,CAAC,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAChE,CAAC;IAED;;;;OAIG;IACI,IAAI,CAAC,KAAa;QACxB,IAAI,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,SAAS,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACxC,OAAO,GAAG,CAAC;QACZ,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,KAAa;QACzB,MAAM,CAAC,eAAe,CAAC,wBAAwB,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC;CACD","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IContextIdHandler } from \"@3sixty/context\";\nimport { Converter, Guards, Is } from \"@3sixty/core\";\n\n\n/**\n * Context ID handler that treats a tenant ID as a compact base64url-encoded hex string.\n */\nexport class TenantIdContextIdHandler implements IContextIdHandler {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = \"TenantIdContextIdHandler\";\n\n\t/**\n\t * The class name of the component.\n\t * @returns The class name.\n\t */\n\tpublic className(): string {\n\t\treturn TenantIdContextIdHandler.CLASS_NAME;\n\t}\n\n\t/**\n\t * The short form of the tenant id is the base64 version to compact.\n\t * @param value The full context id value.\n\t * @returns Short form string.\n\t */\n\tpublic short(value: string): string {\n\t\treturn Converter.bytesToBase64Url(Converter.hexToBytes(value));\n\t}\n\n\t/**\n\t * The long form version of the context ID, expanded from a short version.\n\t * @param value The short form context ID value.\n\t * @returns The long form version of the context ID.\n\t */\n\tpublic long(value: string): string {\n\t\tif (Is.stringBase64Url(value)) {\n\t\t\tconst bytes = Converter.base64UrlToBytes(value);\n\t\t\tconst hex = Converter.bytesToHex(bytes);\n\t\t\treturn hex;\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Guard the value ensuring length.\n\t * @param value The value to guard.\n\t * @throws GeneralError if the value is too short.\n\t */\n\tpublic guard(value: string): void {\n\t\tGuards.stringHexLength(TenantIdContextIdHandler.CLASS_NAME, \"value\", value, 32);\n\t}\n}\n"]}
|