@twin.org/api-tenant-processor 0.0.3-next.27 → 0.0.3-next.29

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ITenantProcessorConstructorOptions.js","sourceRoot":"","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 entity storage for the tenants.\n\t * @default tenant\n\t */\n\ttenantEntityStorageType?: string;\n\n\t/**\n\t * Configuration for the processor.\n\t */\n\tconfig?: ITenantProcessorConfig;\n}\n"]}
1
+ {"version":3,"file":"ITenantProcessorConstructorOptions.js","sourceRoot":"","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 entity storage for the tenants.\n\t * @default tenant\n\t */\n\ttenantEntityStorageType?: string;\n\n\t/**\n\t * The hosting component for the tenants.\n\t * @default hosting\n\t */\n\thostingComponentType?: string;\n\n\t/**\n\t * Configuration for the processor.\n\t */\n\tconfig?: ITenantProcessorConfig;\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
3
  import { HttpErrorHelper } from "@twin.org/api-models";
4
4
  import { ContextIdKeys } from "@twin.org/context";
5
- import { BaseError, Is, UnauthorizedError } from "@twin.org/core";
5
+ import { BaseError, ComponentFactory, Is, UnauthorizedError } from "@twin.org/core";
6
6
  import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
7
7
  import { HttpStatusCode } from "@twin.org/web";
8
8
  /**
@@ -23,17 +23,23 @@ export class TenantProcessor {
23
23
  * @internal
24
24
  */
25
25
  _entityStorageConnector;
26
+ /**
27
+ * The hosting component, used to resolve public origins for tenants and encrypt/decrypt tenant tokens.
28
+ * @internal
29
+ */
30
+ _hostingComponent;
26
31
  /**
27
32
  * The key in the header to look for the api key.
28
33
  * @internal
29
34
  */
30
35
  _apiKeyName;
31
36
  /**
32
- * Create a new instance of NodeTenantProcessor.
37
+ * Create a new instance of TenantProcessor.
33
38
  * @param options Options for the processor.
34
39
  */
35
40
  constructor(options) {
36
41
  this._entityStorageConnector = EntityStorageConnectorFactory.get(options?.tenantEntityStorageType ?? "tenant");
42
+ this._hostingComponent = ComponentFactory.get(options?.hostingComponentType ?? "hosting");
37
43
  this._apiKeyName = options?.config?.apiKeyName ?? TenantProcessor.DEFAULT_API_KEY_NAME;
38
44
  }
39
45
  /**
@@ -53,36 +59,65 @@ export class TenantProcessor {
53
59
  */
54
60
  async pre(request, response, route, contextIds, processorState) {
55
61
  if (!Is.empty(route) && !(route.skipTenant ?? false)) {
56
- const apiKey = request.headers?.[this._apiKeyName] ?? request.query?.[this._apiKeyName];
57
- let errorResponse;
58
- if (Is.stringValue(apiKey)) {
59
- try {
60
- const nodeTenant = await this._entityStorageConnector.get(apiKey, "apiKey");
61
- if (Is.empty(nodeTenant)) {
62
- errorResponse = new UnauthorizedError(TenantProcessor.CLASS_NAME, "apiKeyNotFound", {
63
- key: apiKey
64
- });
62
+ try {
63
+ const apiKey = request.headers?.[this._apiKeyName] ?? request.query?.[this._apiKeyName];
64
+ let tenant;
65
+ // First check apiKey as this is the most common way to authenticate tenants,
66
+ // if that is not present check for the tenant token query param which is used
67
+ // in scenarios where there is an embedded static token.
68
+ if (Is.stringValue(apiKey)) {
69
+ tenant = await this.resolveByApiKey(apiKey);
70
+ }
71
+ else {
72
+ const tenantToken = await this._hostingComponent.getTenantTokenFromQueryParams(request.query);
73
+ if (Is.stringValue(tenantToken)) {
74
+ tenant = await this.resolveByTenantToken(tenantToken);
65
75
  }
66
76
  else {
67
- contextIds[ContextIdKeys.Tenant] = nodeTenant.id;
68
- if (Is.stringValue(nodeTenant.publicOrigin)) {
69
- processorState.publicOrigin = nodeTenant.publicOrigin;
70
- }
77
+ throw new UnauthorizedError(TenantProcessor.CLASS_NAME, "missingApiKeyOrTenantToken", {
78
+ keyName: this._apiKeyName
79
+ });
71
80
  }
72
81
  }
73
- catch (err) {
74
- errorResponse = BaseError.fromError(err);
82
+ contextIds[ContextIdKeys.Tenant] = tenant.id;
83
+ if (Is.stringValue(tenant.publicOrigin)) {
84
+ processorState.publicOrigin = tenant.publicOrigin;
75
85
  }
76
86
  }
77
- else {
78
- errorResponse = new UnauthorizedError(TenantProcessor.CLASS_NAME, "missingApiKey", {
79
- keyName: this._apiKeyName
80
- });
81
- }
82
- if (!Is.empty(errorResponse)) {
83
- HttpErrorHelper.buildResponse(response, errorResponse, HttpStatusCode.unauthorized);
87
+ catch (err) {
88
+ HttpErrorHelper.buildResponse(response, BaseError.fromError(err), HttpStatusCode.unauthorized);
84
89
  }
85
90
  }
86
91
  }
92
+ /**
93
+ * Resolve the tenant context from an api key.
94
+ * @param apiKey The api key sent by the caller.
95
+ * @returns The tenant associated with the api key.
96
+ * @internal
97
+ */
98
+ async resolveByApiKey(apiKey) {
99
+ const nodeTenant = await this._entityStorageConnector.get(apiKey, "apiKey");
100
+ if (Is.empty(nodeTenant)) {
101
+ throw new UnauthorizedError(TenantProcessor.CLASS_NAME, "apiKeyNotFound", {
102
+ key: apiKey
103
+ });
104
+ }
105
+ return nodeTenant;
106
+ }
107
+ /**
108
+ * Resolve the tenant context from an encrypted tenant token query param.
109
+ * @param tenantId The encrypted tenant token.
110
+ * @returns The tenant associated with the tenant token.
111
+ * @internal
112
+ */
113
+ async resolveByTenantToken(tenantId) {
114
+ const nodeTenant = await this._entityStorageConnector.get(tenantId);
115
+ if (Is.empty(nodeTenant)) {
116
+ throw new UnauthorizedError(TenantProcessor.CLASS_NAME, "tenantNotFound", {
117
+ tenantId
118
+ });
119
+ }
120
+ return nodeTenant;
121
+ }
87
122
  }
88
123
  //# sourceMappingURL=tenantProcessor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tenantProcessor.js","sourceRoot":"","sources":["../../src/tenantProcessor.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EACN,eAAe,EAKf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAoB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAe,EAAE,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EACN,6BAA6B,EAE7B,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAI/C;;GAEG;AACH,MAAM,OAAO,eAAe;IAC3B;;;OAGG;IACI,MAAM,CAAU,oBAAoB,GAAW,WAAW,CAAC;IAElE;;OAEG;IACI,MAAM,CAAU,UAAU,qBAAqC;IAEtE;;;OAGG;IACc,uBAAuB,CAAkC;IAE1E;;;OAGG;IACc,WAAW,CAAS;IAErC;;;OAGG;IACH,YAAY,OAA4C;QACvD,IAAI,CAAC,uBAAuB,GAAG,6BAA6B,CAAC,GAAG,CAC/D,OAAO,EAAE,uBAAuB,IAAI,QAAQ,CAC5C,CAAC;QACF,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,IAAI,eAAe,CAAC,oBAAoB,CAAC;IACxF,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,eAAe,CAAC,UAAU,CAAC;IACnC,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,GAAG,CACf,OAA2B,EAC3B,QAAuB,EACvB,KAA6B,EAC7B,UAAuB,EACvB,cAAyC;QAEzC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,EAAE,CAAC;YACtD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACxF,IAAI,aAAiC,CAAC;YAEtC,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC;oBACJ,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;oBAE5E,IAAI,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;wBAC1B,aAAa,GAAG,IAAI,iBAAiB,CAAC,eAAe,CAAC,UAAU,EAAE,gBAAgB,EAAE;4BACnF,GAAG,EAAE,MAAM;yBACX,CAAC,CAAC;oBACJ,CAAC;yBAAM,CAAC;wBACP,UAAU,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC;wBACjD,IAAI,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;4BAC7C,cAAc,CAAC,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC;wBACvD,CAAC;oBACF,CAAC;gBACF,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,aAAa,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC1C,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,aAAa,GAAG,IAAI,iBAAiB,CAAC,eAAe,CAAC,UAAU,EAAE,eAAe,EAAE;oBAClF,OAAO,EAAE,IAAI,CAAC,WAAW;iBACzB,CAAC,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC9B,eAAe,CAAC,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;YACrF,CAAC;QACF,CAAC;IACF,CAAC","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 \"@twin.org/api-models\";\nimport { ContextIdKeys, type IContextIds } from \"@twin.org/context\";\nimport { BaseError, type IError, Is, UnauthorizedError } from \"@twin.org/core\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HttpStatusCode } from \"@twin.org/web\";\nimport type { Tenant } from \"./entities/tenant.js\";\nimport type { ITenantProcessorConstructorOptions } from \"./models/ITenantProcessorConstructorOptions.js\";\n\n/**\n * Handles incoming api keys and maps them to tenant ids.\n */\nexport class TenantProcessor implements IBaseRouteProcessor {\n\t/**\n\t * The default name for the api key header.\n\t * @internal\n\t */\n\tpublic static readonly DEFAULT_API_KEY_NAME: string = \"x-api-key\";\n\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TenantProcessor>();\n\n\t/**\n\t * The entity storage for api keys.\n\t * @internal\n\t */\n\tprivate readonly _entityStorageConnector: IEntityStorageConnector<Tenant>;\n\n\t/**\n\t * The key in the header to look for the api key.\n\t * @internal\n\t */\n\tprivate readonly _apiKeyName: string;\n\n\t/**\n\t * Create a new instance of NodeTenantProcessor.\n\t * @param options Options for the processor.\n\t */\n\tconstructor(options?: ITenantProcessorConstructorOptions) {\n\t\tthis._entityStorageConnector = EntityStorageConnectorFactory.get(\n\t\t\toptions?.tenantEntityStorageType ?? \"tenant\"\n\t\t);\n\t\tthis._apiKeyName = options?.config?.apiKeyName ?? TenantProcessor.DEFAULT_API_KEY_NAME;\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 TenantProcessor.CLASS_NAME;\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 */\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\tif (!Is.empty(route) && !(route.skipTenant ?? false)) {\n\t\t\tconst apiKey = request.headers?.[this._apiKeyName] ?? request.query?.[this._apiKeyName];\n\t\t\tlet errorResponse: IError | undefined;\n\n\t\t\tif (Is.stringValue(apiKey)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst nodeTenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\n\t\t\t\t\tif (Is.empty(nodeTenant)) {\n\t\t\t\t\t\terrorResponse = new UnauthorizedError(TenantProcessor.CLASS_NAME, \"apiKeyNotFound\", {\n\t\t\t\t\t\t\tkey: apiKey\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontextIds[ContextIdKeys.Tenant] = nodeTenant.id;\n\t\t\t\t\t\tif (Is.stringValue(nodeTenant.publicOrigin)) {\n\t\t\t\t\t\t\tprocessorState.publicOrigin = nodeTenant.publicOrigin;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\terrorResponse = BaseError.fromError(err);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\terrorResponse = new UnauthorizedError(TenantProcessor.CLASS_NAME, \"missingApiKey\", {\n\t\t\t\t\tkeyName: this._apiKeyName\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!Is.empty(errorResponse)) {\n\t\t\t\tHttpErrorHelper.buildResponse(response, errorResponse, HttpStatusCode.unauthorized);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"tenantProcessor.js","sourceRoot":"","sources":["../../src/tenantProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\tHttpErrorHelper,\n\ttype IBaseRoute,\n\ttype IBaseRouteProcessor,\n\ttype IHostingComponent,\n\ttype IHttpResponse,\n\ttype IHttpServerRequest\n} from \"@twin.org/api-models\";\nimport { ContextIdKeys, type IContextIds } from \"@twin.org/context\";\nimport { BaseError, ComponentFactory, Is, UnauthorizedError } from \"@twin.org/core\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HttpStatusCode } from \"@twin.org/web\";\nimport type { Tenant } from \"./entities/tenant.js\";\nimport type { ITenantProcessorConstructorOptions } from \"./models/ITenantProcessorConstructorOptions.js\";\n\n/**\n * Handles incoming api keys and maps them to tenant ids.\n */\nexport class TenantProcessor implements IBaseRouteProcessor {\n\t/**\n\t * The default name for the api key header.\n\t * @internal\n\t */\n\tpublic static readonly DEFAULT_API_KEY_NAME: string = \"x-api-key\";\n\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TenantProcessor>();\n\n\t/**\n\t * The entity storage for api keys.\n\t * @internal\n\t */\n\tprivate readonly _entityStorageConnector: IEntityStorageConnector<Tenant>;\n\n\t/**\n\t * The hosting component, used to resolve public origins for tenants and encrypt/decrypt tenant tokens.\n\t * @internal\n\t */\n\tprivate readonly _hostingComponent: IHostingComponent;\n\n\t/**\n\t * The key in the header to look for the api key.\n\t * @internal\n\t */\n\tprivate readonly _apiKeyName: string;\n\n\t/**\n\t * Create a new instance of TenantProcessor.\n\t * @param options Options for the processor.\n\t */\n\tconstructor(options?: ITenantProcessorConstructorOptions) {\n\t\tthis._entityStorageConnector = EntityStorageConnectorFactory.get(\n\t\t\toptions?.tenantEntityStorageType ?? \"tenant\"\n\t\t);\n\t\tthis._hostingComponent = ComponentFactory.get(options?.hostingComponentType ?? \"hosting\");\n\t\tthis._apiKeyName = options?.config?.apiKeyName ?? TenantProcessor.DEFAULT_API_KEY_NAME;\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 TenantProcessor.CLASS_NAME;\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 */\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\tif (!Is.empty(route) && !(route.skipTenant ?? false)) {\n\t\t\ttry {\n\t\t\t\tconst apiKey = request.headers?.[this._apiKeyName] ?? request.query?.[this._apiKeyName];\n\t\t\t\tlet tenant;\n\n\t\t\t\t// First check apiKey as this is the most common way to authenticate tenants,\n\t\t\t\t// if that is not present check for the tenant token query param which is used\n\t\t\t\t// in scenarios where there is an embedded static token.\n\t\t\t\tif (Is.stringValue(apiKey)) {\n\t\t\t\t\ttenant = await this.resolveByApiKey(apiKey);\n\t\t\t\t} else {\n\t\t\t\t\tconst tenantToken = await this._hostingComponent.getTenantTokenFromQueryParams(\n\t\t\t\t\t\trequest.query\n\t\t\t\t\t);\n\n\t\t\t\t\tif (Is.stringValue(tenantToken)) {\n\t\t\t\t\t\ttenant = await this.resolveByTenantToken(tenantToken);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new UnauthorizedError(TenantProcessor.CLASS_NAME, \"missingApiKeyOrTenantToken\", {\n\t\t\t\t\t\t\tkeyName: this._apiKeyName\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcontextIds[ContextIdKeys.Tenant] = tenant.id;\n\t\t\t\tif (Is.stringValue(tenant.publicOrigin)) {\n\t\t\t\t\tprocessorState.publicOrigin = tenant.publicOrigin;\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);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Resolve the tenant context from an api key.\n\t * @param apiKey The api key sent by the caller.\n\t * @returns The tenant associated with the api key.\n\t * @internal\n\t */\n\tprivate async resolveByApiKey(apiKey: string): Promise<Tenant> {\n\t\tconst nodeTenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\n\t\tif (Is.empty(nodeTenant)) {\n\t\t\tthrow new UnauthorizedError(TenantProcessor.CLASS_NAME, \"apiKeyNotFound\", {\n\t\t\t\tkey: apiKey\n\t\t\t});\n\t\t}\n\n\t\treturn nodeTenant;\n\t}\n\n\t/**\n\t * Resolve the tenant context from an encrypted tenant token query param.\n\t * @param tenantId The encrypted tenant token.\n\t * @returns The tenant associated with the tenant token.\n\t * @internal\n\t */\n\tprivate async resolveByTenantToken(tenantId: string): Promise<Tenant> {\n\t\tconst nodeTenant = await this._entityStorageConnector.get(tenantId);\n\n\t\tif (Is.empty(nodeTenant)) {\n\t\t\tthrow new UnauthorizedError(TenantProcessor.CLASS_NAME, \"tenantNotFound\", {\n\t\t\t\ttenantId\n\t\t\t});\n\t\t}\n\n\t\treturn nodeTenant;\n\t}\n}\n"]}
@@ -8,6 +8,11 @@ export interface ITenantProcessorConstructorOptions {
8
8
  * @default tenant
9
9
  */
10
10
  tenantEntityStorageType?: string;
11
+ /**
12
+ * The hosting component for the tenants.
13
+ * @default hosting
14
+ */
15
+ hostingComponentType?: string;
11
16
  /**
12
17
  * Configuration for the processor.
13
18
  */
@@ -10,7 +10,7 @@ export declare class TenantProcessor implements IBaseRouteProcessor {
10
10
  */
11
11
  static readonly CLASS_NAME: string;
12
12
  /**
13
- * Create a new instance of NodeTenantProcessor.
13
+ * Create a new instance of TenantProcessor.
14
14
  * @param options Options for the processor.
15
15
  */
16
16
  constructor(options?: ITenantProcessorConstructorOptions);
package/docs/changelog.md CHANGED
@@ -1,6 +1,34 @@
1
1
  # Changelog
2
2
 
3
- ## [0.0.3-next.27](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.26...api-tenant-processor-v0.0.3-next.27) (2026-04-23)
3
+ ## [0.0.3-next.29](https://github.com/twinfoundation/twin-api/compare/api-tenant-processor-v0.0.3-next.28...api-tenant-processor-v0.0.3-next.29) (2026-05-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * hosting service ([#109](https://github.com/twinfoundation/twin-api/issues/109)) ([985bf1f](https://github.com/twinfoundation/twin-api/commit/985bf1f5c07b09ecb800df7120bc2422ac7a6d25))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/api-models bumped from 0.0.3-next.28 to 0.0.3-next.29
16
+
17
+ ## [0.0.3-next.28](https://github.com/twinfoundation/twin-api/compare/api-tenant-processor-v0.0.3-next.27...api-tenant-processor-v0.0.3-next.28) (2026-04-30)
18
+
19
+
20
+ ### Features
21
+
22
+ * tenantToken decoder on skipTenant routes + BaseRestClient query-string preservation ([#108](https://github.com/twinfoundation/twin-api/issues/108)) ([1435357](https://github.com/twinfoundation/twin-api/commit/1435357034b41130fc97238c728265e48f746f1e))
23
+
24
+
25
+ ### Dependencies
26
+
27
+ * The following workspace dependencies were updated
28
+ * dependencies
29
+ * @twin.org/api-models bumped from 0.0.3-next.27 to 0.0.3-next.28
30
+
31
+ ## [0.0.3-next.27](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.26...api-tenant-processor-v0.0.3-next.27) (2026-04-23)
4
32
 
5
33
 
6
34
  ### Miscellaneous Chores
@@ -14,7 +42,7 @@
14
42
  * dependencies
15
43
  * @twin.org/api-models bumped from 0.0.3-next.26 to 0.0.3-next.27
16
44
 
17
- ## [0.0.3-next.26](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.25...api-tenant-processor-v0.0.3-next.26) (2026-04-22)
45
+ ## [0.0.3-next.26](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.25...api-tenant-processor-v0.0.3-next.26) (2026-04-22)
18
46
 
19
47
 
20
48
  ### Miscellaneous Chores
@@ -28,7 +56,7 @@
28
56
  * dependencies
29
57
  * @twin.org/api-models bumped from 0.0.3-next.25 to 0.0.3-next.26
30
58
 
31
- ## [0.0.3-next.25](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.24...api-tenant-processor-v0.0.3-next.25) (2026-04-14)
59
+ ## [0.0.3-next.25](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.24...api-tenant-processor-v0.0.3-next.25) (2026-04-14)
32
60
 
33
61
 
34
62
  ### Miscellaneous Chores
@@ -42,7 +70,7 @@
42
70
  * dependencies
43
71
  * @twin.org/api-models bumped from 0.0.3-next.24 to 0.0.3-next.25
44
72
 
45
- ## [0.0.3-next.24](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.23...api-tenant-processor-v0.0.3-next.24) (2026-04-14)
73
+ ## [0.0.3-next.24](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.23...api-tenant-processor-v0.0.3-next.24) (2026-04-14)
46
74
 
47
75
 
48
76
  ### Miscellaneous Chores
@@ -56,7 +84,7 @@
56
84
  * dependencies
57
85
  * @twin.org/api-models bumped from 0.0.3-next.23 to 0.0.3-next.24
58
86
 
59
- ## [0.0.3-next.23](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.22...api-tenant-processor-v0.0.3-next.23) (2026-04-14)
87
+ ## [0.0.3-next.23](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.22...api-tenant-processor-v0.0.3-next.23) (2026-04-14)
60
88
 
61
89
 
62
90
  ### Miscellaneous Chores
@@ -70,7 +98,7 @@
70
98
  * dependencies
71
99
  * @twin.org/api-models bumped from 0.0.3-next.22 to 0.0.3-next.23
72
100
 
73
- ## [0.0.3-next.22](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.21...api-tenant-processor-v0.0.3-next.22) (2026-03-27)
101
+ ## [0.0.3-next.22](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.21...api-tenant-processor-v0.0.3-next.22) (2026-03-27)
74
102
 
75
103
 
76
104
  ### Miscellaneous Chores
@@ -84,7 +112,7 @@
84
112
  * dependencies
85
113
  * @twin.org/api-models bumped from 0.0.3-next.21 to 0.0.3-next.22
86
114
 
87
- ## [0.0.3-next.21](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.20...api-tenant-processor-v0.0.3-next.21) (2026-03-11)
115
+ ## [0.0.3-next.21](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.20...api-tenant-processor-v0.0.3-next.21) (2026-03-11)
88
116
 
89
117
 
90
118
  ### Miscellaneous Chores
@@ -98,12 +126,12 @@
98
126
  * dependencies
99
127
  * @twin.org/api-models bumped from 0.0.3-next.20 to 0.0.3-next.21
100
128
 
101
- ## [0.0.3-next.20](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.19...api-tenant-processor-v0.0.3-next.20) (2026-02-09)
129
+ ## [0.0.3-next.20](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.19...api-tenant-processor-v0.0.3-next.20) (2026-02-09)
102
130
 
103
131
 
104
132
  ### Features
105
133
 
106
- * location encoding ([#79](https://github.com/twinfoundation/api/issues/79)) ([c684465](https://github.com/twinfoundation/api/commit/c684465f2a871376152472bdecb6aa230b1101a1))
134
+ * location encoding ([#79](https://github.com/iotaledger/twin-api/issues/79)) ([c684465](https://github.com/iotaledger/twin-api/commit/c684465f2a871376152472bdecb6aa230b1101a1))
107
135
 
108
136
 
109
137
  ### Dependencies
@@ -112,7 +140,7 @@
112
140
  * dependencies
113
141
  * @twin.org/api-models bumped from 0.0.3-next.19 to 0.0.3-next.20
114
142
 
115
- ## [0.0.3-next.19](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.18...api-tenant-processor-v0.0.3-next.19) (2026-02-06)
143
+ ## [0.0.3-next.19](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.18...api-tenant-processor-v0.0.3-next.19) (2026-02-06)
116
144
 
117
145
 
118
146
  ### Miscellaneous Chores
@@ -126,12 +154,12 @@
126
154
  * dependencies
127
155
  * @twin.org/api-models bumped from 0.0.3-next.18 to 0.0.3-next.19
128
156
 
129
- ## [0.0.3-next.18](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.17...api-tenant-processor-v0.0.3-next.18) (2026-02-04)
157
+ ## [0.0.3-next.18](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.17...api-tenant-processor-v0.0.3-next.18) (2026-02-04)
130
158
 
131
159
 
132
160
  ### Features
133
161
 
134
- * tenant api and scopes ([#75](https://github.com/twinfoundation/api/issues/75)) ([c663141](https://github.com/twinfoundation/api/commit/c663141091e8974d769f8f9904ecdab009ebd083))
162
+ * tenant api and scopes ([#75](https://github.com/iotaledger/twin-api/issues/75)) ([c663141](https://github.com/iotaledger/twin-api/commit/c663141091e8974d769f8f9904ecdab009ebd083))
135
163
 
136
164
 
137
165
  ### Dependencies
@@ -140,7 +168,7 @@
140
168
  * dependencies
141
169
  * @twin.org/api-models bumped from 0.0.3-next.17 to 0.0.3-next.18
142
170
 
143
- ## [0.0.3-next.17](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.16...api-tenant-processor-v0.0.3-next.17) (2026-01-26)
171
+ ## [0.0.3-next.17](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.16...api-tenant-processor-v0.0.3-next.17) (2026-01-26)
144
172
 
145
173
 
146
174
  ### Miscellaneous Chores
@@ -154,12 +182,12 @@
154
182
  * dependencies
155
183
  * @twin.org/api-models bumped from 0.0.3-next.16 to 0.0.3-next.17
156
184
 
157
- ## [0.0.3-next.16](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.15...api-tenant-processor-v0.0.3-next.16) (2026-01-26)
185
+ ## [0.0.3-next.16](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.15...api-tenant-processor-v0.0.3-next.16) (2026-01-26)
158
186
 
159
187
 
160
188
  ### Features
161
189
 
162
- * public base url ([#70](https://github.com/twinfoundation/api/issues/70)) ([5b958cd](https://github.com/twinfoundation/api/commit/5b958cd91e8a38cdae2835ff5f2356c7e48d37c3))
190
+ * public base url ([#70](https://github.com/iotaledger/twin-api/issues/70)) ([5b958cd](https://github.com/iotaledger/twin-api/commit/5b958cd91e8a38cdae2835ff5f2356c7e48d37c3))
163
191
 
164
192
 
165
193
  ### Dependencies
@@ -168,7 +196,7 @@
168
196
  * dependencies
169
197
  * @twin.org/api-models bumped from 0.0.3-next.15 to 0.0.3-next.16
170
198
 
171
- ## [0.0.3-next.15](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.14...api-tenant-processor-v0.0.3-next.15) (2026-01-22)
199
+ ## [0.0.3-next.15](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.14...api-tenant-processor-v0.0.3-next.15) (2026-01-22)
172
200
 
173
201
 
174
202
  ### Miscellaneous Chores
@@ -182,7 +210,7 @@
182
210
  * dependencies
183
211
  * @twin.org/api-models bumped from 0.0.3-next.14 to 0.0.3-next.15
184
212
 
185
- ## [0.0.3-next.14](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.13...api-tenant-processor-v0.0.3-next.14) (2026-01-20)
213
+ ## [0.0.3-next.14](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.13...api-tenant-processor-v0.0.3-next.14) (2026-01-20)
186
214
 
187
215
 
188
216
  ### Miscellaneous Chores
@@ -196,7 +224,7 @@
196
224
  * dependencies
197
225
  * @twin.org/api-models bumped from 0.0.3-next.13 to 0.0.3-next.14
198
226
 
199
- ## [0.0.3-next.13](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.12...api-tenant-processor-v0.0.3-next.13) (2026-01-19)
227
+ ## [0.0.3-next.13](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.12...api-tenant-processor-v0.0.3-next.13) (2026-01-19)
200
228
 
201
229
 
202
230
  ### Miscellaneous Chores
@@ -210,7 +238,7 @@
210
238
  * dependencies
211
239
  * @twin.org/api-models bumped from 0.0.3-next.12 to 0.0.3-next.13
212
240
 
213
- ## [0.0.3-next.12](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.11...api-tenant-processor-v0.0.3-next.12) (2026-01-12)
241
+ ## [0.0.3-next.12](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.11...api-tenant-processor-v0.0.3-next.12) (2026-01-12)
214
242
 
215
243
 
216
244
  ### Miscellaneous Chores
@@ -224,12 +252,12 @@
224
252
  * dependencies
225
253
  * @twin.org/api-models bumped from 0.0.3-next.11 to 0.0.3-next.12
226
254
 
227
- ## [0.0.3-next.11](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.10...api-tenant-processor-v0.0.3-next.11) (2026-01-08)
255
+ ## [0.0.3-next.11](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.10...api-tenant-processor-v0.0.3-next.11) (2026-01-08)
228
256
 
229
257
 
230
258
  ### Bug Fixes
231
259
 
232
- * duplicate api keys ([#61](https://github.com/twinfoundation/api/issues/61)) ([5519c2d](https://github.com/twinfoundation/api/commit/5519c2d077d9b3d4b5fc7d5f073ef67cd000a367))
260
+ * duplicate api keys ([#61](https://github.com/iotaledger/twin-api/issues/61)) ([5519c2d](https://github.com/iotaledger/twin-api/commit/5519c2d077d9b3d4b5fc7d5f073ef67cd000a367))
233
261
 
234
262
 
235
263
  ### Dependencies
@@ -238,7 +266,7 @@
238
266
  * dependencies
239
267
  * @twin.org/api-models bumped from 0.0.3-next.10 to 0.0.3-next.11
240
268
 
241
- ## [0.0.3-next.10](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.9...api-tenant-processor-v0.0.3-next.10) (2026-01-05)
269
+ ## [0.0.3-next.10](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.9...api-tenant-processor-v0.0.3-next.10) (2026-01-05)
242
270
 
243
271
 
244
272
  ### Miscellaneous Chores
@@ -252,24 +280,24 @@
252
280
  * dependencies
253
281
  * @twin.org/api-models bumped from 0.0.3-next.9 to 0.0.3-next.10
254
282
 
255
- ## [0.0.3-next.9](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.8...api-tenant-processor-v0.0.3-next.9) (2026-01-05)
283
+ ## [0.0.3-next.9](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.8...api-tenant-processor-v0.0.3-next.9) (2026-01-05)
256
284
 
257
285
 
258
286
  ### Features
259
287
 
260
- * add context id features ([#42](https://github.com/twinfoundation/api/issues/42)) ([0186055](https://github.com/twinfoundation/api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
261
- * add livez endpoint ([#57](https://github.com/twinfoundation/api/issues/57)) ([ef007db](https://github.com/twinfoundation/api/commit/ef007db8201736dd3053211f849ffd03baaa485e))
262
- * add tests for tenant id handler ([c868e7e](https://github.com/twinfoundation/api/commit/c868e7e5831e13df39b8994c40834e51f69fa0b9))
263
- * check tenant id in auth if set ([937ba0c](https://github.com/twinfoundation/api/commit/937ba0cd790038556a7b2af251e52b43cb059df4))
264
- * check tenant id in auth if set ([66f7337](https://github.com/twinfoundation/api/commit/66f73374d3cf4c1c85ea96ec74bb30712fb84dd7))
265
- * reduce short form tenant id length ([bcda377](https://github.com/twinfoundation/api/commit/bcda377daed03b21fd1c6ffe47bad4a45d96602b))
288
+ * add context id features ([#42](https://github.com/iotaledger/twin-api/issues/42)) ([0186055](https://github.com/iotaledger/twin-api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
289
+ * add livez endpoint ([#57](https://github.com/iotaledger/twin-api/issues/57)) ([ef007db](https://github.com/iotaledger/twin-api/commit/ef007db8201736dd3053211f849ffd03baaa485e))
290
+ * add tests for tenant id handler ([c868e7e](https://github.com/iotaledger/twin-api/commit/c868e7e5831e13df39b8994c40834e51f69fa0b9))
291
+ * check tenant id in auth if set ([937ba0c](https://github.com/iotaledger/twin-api/commit/937ba0cd790038556a7b2af251e52b43cb059df4))
292
+ * check tenant id in auth if set ([66f7337](https://github.com/iotaledger/twin-api/commit/66f73374d3cf4c1c85ea96ec74bb30712fb84dd7))
293
+ * reduce short form tenant id length ([bcda377](https://github.com/iotaledger/twin-api/commit/bcda377daed03b21fd1c6ffe47bad4a45d96602b))
266
294
 
267
295
 
268
296
  ### Bug Fixes
269
297
 
270
- * do not check x-api-key for health resourcr ([#54](https://github.com/twinfoundation/api/issues/54)) ([897a747](https://github.com/twinfoundation/api/commit/897a747a57ed76ee37035f7ea3d40953df3f5fb0))
271
- * remove extraneous type ([f85c52c](https://github.com/twinfoundation/api/commit/f85c52c55caa3a7a64f6f675842f0ea59289a5d9))
272
- * use base64Url for tenant id short form so it doesn't include slash ([7210771](https://github.com/twinfoundation/api/commit/72107718650acd05440ce9d9bf10905e6052281c))
298
+ * do not check x-api-key for health resourcr ([#54](https://github.com/iotaledger/twin-api/issues/54)) ([897a747](https://github.com/iotaledger/twin-api/commit/897a747a57ed76ee37035f7ea3d40953df3f5fb0))
299
+ * remove extraneous type ([f85c52c](https://github.com/iotaledger/twin-api/commit/f85c52c55caa3a7a64f6f675842f0ea59289a5d9))
300
+ * use base64Url for tenant id short form so it doesn't include slash ([7210771](https://github.com/iotaledger/twin-api/commit/72107718650acd05440ce9d9bf10905e6052281c))
273
301
 
274
302
 
275
303
  ### Dependencies
@@ -278,12 +306,12 @@
278
306
  * dependencies
279
307
  * @twin.org/api-models bumped from 0.0.3-next.8 to 0.0.3-next.9
280
308
 
281
- ## [0.0.3-next.8](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.7...api-tenant-processor-v0.0.3-next.8) (2025-12-17)
309
+ ## [0.0.3-next.8](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.7...api-tenant-processor-v0.0.3-next.8) (2025-12-17)
282
310
 
283
311
 
284
312
  ### Bug Fixes
285
313
 
286
- * do not check x-api-key for health resourcr ([#54](https://github.com/twinfoundation/api/issues/54)) ([897a747](https://github.com/twinfoundation/api/commit/897a747a57ed76ee37035f7ea3d40953df3f5fb0))
314
+ * do not check x-api-key for health resourcr ([#54](https://github.com/iotaledger/twin-api/issues/54)) ([897a747](https://github.com/iotaledger/twin-api/commit/897a747a57ed76ee37035f7ea3d40953df3f5fb0))
287
315
 
288
316
 
289
317
  ### Dependencies
@@ -292,7 +320,7 @@
292
320
  * dependencies
293
321
  * @twin.org/api-models bumped from 0.0.3-next.7 to 0.0.3-next.8
294
322
 
295
- ## [0.0.3-next.7](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.6...api-tenant-processor-v0.0.3-next.7) (2025-11-26)
323
+ ## [0.0.3-next.7](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.6...api-tenant-processor-v0.0.3-next.7) (2025-11-26)
296
324
 
297
325
 
298
326
  ### Miscellaneous Chores
@@ -306,13 +334,13 @@
306
334
  * dependencies
307
335
  * @twin.org/api-models bumped from 0.0.3-next.6 to 0.0.3-next.7
308
336
 
309
- ## [0.0.3-next.6](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.5...api-tenant-processor-v0.0.3-next.6) (2025-11-20)
337
+ ## [0.0.3-next.6](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.5...api-tenant-processor-v0.0.3-next.6) (2025-11-20)
310
338
 
311
339
 
312
340
  ### Features
313
341
 
314
- * check tenant id in auth if set ([937ba0c](https://github.com/twinfoundation/api/commit/937ba0cd790038556a7b2af251e52b43cb059df4))
315
- * check tenant id in auth if set ([66f7337](https://github.com/twinfoundation/api/commit/66f73374d3cf4c1c85ea96ec74bb30712fb84dd7))
342
+ * check tenant id in auth if set ([937ba0c](https://github.com/iotaledger/twin-api/commit/937ba0cd790038556a7b2af251e52b43cb059df4))
343
+ * check tenant id in auth if set ([66f7337](https://github.com/iotaledger/twin-api/commit/66f73374d3cf4c1c85ea96ec74bb30712fb84dd7))
316
344
 
317
345
 
318
346
  ### Dependencies
@@ -321,7 +349,7 @@
321
349
  * dependencies
322
350
  * @twin.org/api-models bumped from 0.0.3-next.5 to 0.0.3-next.6
323
351
 
324
- ## [0.0.3-next.5](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.4...api-tenant-processor-v0.0.3-next.5) (2025-11-14)
352
+ ## [0.0.3-next.5](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.4...api-tenant-processor-v0.0.3-next.5) (2025-11-14)
325
353
 
326
354
 
327
355
  ### Miscellaneous Chores
@@ -335,20 +363,20 @@
335
363
  * dependencies
336
364
  * @twin.org/api-models bumped from 0.0.3-next.4 to 0.0.3-next.5
337
365
 
338
- ## [0.0.3-next.4](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.3...api-tenant-processor-v0.0.3-next.4) (2025-11-14)
366
+ ## [0.0.3-next.4](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.3...api-tenant-processor-v0.0.3-next.4) (2025-11-14)
339
367
 
340
368
 
341
369
  ### Features
342
370
 
343
- * add context id features ([#42](https://github.com/twinfoundation/api/issues/42)) ([0186055](https://github.com/twinfoundation/api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
344
- * add tests for tenant id handler ([c868e7e](https://github.com/twinfoundation/api/commit/c868e7e5831e13df39b8994c40834e51f69fa0b9))
345
- * reduce short form tenant id length ([bcda377](https://github.com/twinfoundation/api/commit/bcda377daed03b21fd1c6ffe47bad4a45d96602b))
371
+ * add context id features ([#42](https://github.com/iotaledger/twin-api/issues/42)) ([0186055](https://github.com/iotaledger/twin-api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
372
+ * add tests for tenant id handler ([c868e7e](https://github.com/iotaledger/twin-api/commit/c868e7e5831e13df39b8994c40834e51f69fa0b9))
373
+ * reduce short form tenant id length ([bcda377](https://github.com/iotaledger/twin-api/commit/bcda377daed03b21fd1c6ffe47bad4a45d96602b))
346
374
 
347
375
 
348
376
  ### Bug Fixes
349
377
 
350
- * remove extraneous type ([f85c52c](https://github.com/twinfoundation/api/commit/f85c52c55caa3a7a64f6f675842f0ea59289a5d9))
351
- * use base64Url for tenant id short form so it doesn't include slash ([7210771](https://github.com/twinfoundation/api/commit/72107718650acd05440ce9d9bf10905e6052281c))
378
+ * remove extraneous type ([f85c52c](https://github.com/iotaledger/twin-api/commit/f85c52c55caa3a7a64f6f675842f0ea59289a5d9))
379
+ * use base64Url for tenant id short form so it doesn't include slash ([7210771](https://github.com/iotaledger/twin-api/commit/72107718650acd05440ce9d9bf10905e6052281c))
352
380
 
353
381
 
354
382
  ### Dependencies
@@ -357,17 +385,17 @@
357
385
  * dependencies
358
386
  * @twin.org/api-models bumped from 0.0.3-next.3 to 0.0.3-next.4
359
387
 
360
- ## [0.0.3-next.3](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.2...api-tenant-processor-v0.0.3-next.3) (2025-11-14)
388
+ ## [0.0.3-next.3](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.2...api-tenant-processor-v0.0.3-next.3) (2025-11-14)
361
389
 
362
390
 
363
391
  ### Features
364
392
 
365
- * add tests for tenant id handler ([c868e7e](https://github.com/twinfoundation/api/commit/c868e7e5831e13df39b8994c40834e51f69fa0b9))
393
+ * add tests for tenant id handler ([c868e7e](https://github.com/iotaledger/twin-api/commit/c868e7e5831e13df39b8994c40834e51f69fa0b9))
366
394
 
367
395
 
368
396
  ### Bug Fixes
369
397
 
370
- * use base64Url for tenant id short form so it doesn't include slash ([7210771](https://github.com/twinfoundation/api/commit/72107718650acd05440ce9d9bf10905e6052281c))
398
+ * use base64Url for tenant id short form so it doesn't include slash ([7210771](https://github.com/iotaledger/twin-api/commit/72107718650acd05440ce9d9bf10905e6052281c))
371
399
 
372
400
 
373
401
  ### Dependencies
@@ -376,17 +404,17 @@
376
404
  * dependencies
377
405
  * @twin.org/api-models bumped from 0.0.3-next.2 to 0.0.3-next.3
378
406
 
379
- ## [0.0.3-next.2](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.1...api-tenant-processor-v0.0.3-next.2) (2025-11-12)
407
+ ## [0.0.3-next.2](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.1...api-tenant-processor-v0.0.3-next.2) (2025-11-12)
380
408
 
381
409
 
382
410
  ### Features
383
411
 
384
- * reduce short form tenant id length ([bcda377](https://github.com/twinfoundation/api/commit/bcda377daed03b21fd1c6ffe47bad4a45d96602b))
412
+ * reduce short form tenant id length ([bcda377](https://github.com/iotaledger/twin-api/commit/bcda377daed03b21fd1c6ffe47bad4a45d96602b))
385
413
 
386
414
 
387
415
  ### Bug Fixes
388
416
 
389
- * remove extraneous type ([f85c52c](https://github.com/twinfoundation/api/commit/f85c52c55caa3a7a64f6f675842f0ea59289a5d9))
417
+ * remove extraneous type ([f85c52c](https://github.com/iotaledger/twin-api/commit/f85c52c55caa3a7a64f6f675842f0ea59289a5d9))
390
418
 
391
419
 
392
420
  ### Dependencies
@@ -395,12 +423,12 @@
395
423
  * dependencies
396
424
  * @twin.org/api-models bumped from 0.0.3-next.1 to 0.0.3-next.2
397
425
 
398
- ## [0.0.3-next.1](https://github.com/twinfoundation/api/compare/api-tenant-processor-v0.0.3-next.0...api-tenant-processor-v0.0.3-next.1) (2025-11-10)
426
+ ## [0.0.3-next.1](https://github.com/iotaledger/twin-api/compare/api-tenant-processor-v0.0.3-next.0...api-tenant-processor-v0.0.3-next.1) (2025-11-10)
399
427
 
400
428
 
401
429
  ### Features
402
430
 
403
- * add context id features ([#42](https://github.com/twinfoundation/api/issues/42)) ([0186055](https://github.com/twinfoundation/api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
431
+ * add context id features ([#42](https://github.com/iotaledger/twin-api/issues/42)) ([0186055](https://github.com/iotaledger/twin-api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
404
432
 
405
433
 
406
434
  ### Dependencies
@@ -12,7 +12,7 @@ Handles incoming api keys and maps them to tenant ids.
12
12
 
13
13
  > **new TenantProcessor**(`options?`): `TenantProcessor`
14
14
 
15
- Create a new instance of NodeTenantProcessor.
15
+ Create a new instance of TenantProcessor.
16
16
 
17
17
  #### Parameters
18
18
 
@@ -18,6 +18,20 @@ tenant
18
18
 
19
19
  ***
20
20
 
21
+ ### hostingComponentType? {#hostingcomponenttype}
22
+
23
+ > `optional` **hostingComponentType?**: `string`
24
+
25
+ The hosting component for the tenants.
26
+
27
+ #### Default
28
+
29
+ ```ts
30
+ hosting
31
+ ```
32
+
33
+ ***
34
+
21
35
  ### config? {#config}
22
36
 
23
37
  > `optional` **config?**: [`ITenantProcessorConfig`](ITenantProcessorConfig.md)
package/locales/en.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "error": {
3
3
  "tenantProcessor": {
4
- "missingApiKey": "API key header or query param \"{keyName}\" is missing or invalid.",
5
- "apiKeyNotFound": "No node tenant found for API key \"{key}\"."
4
+ "missingApiKeyOrTenantToken": "API key \"{keyName}\" or tenant token is missing",
5
+ "apiKeyNotFound": "No node tenant found for API key \"{key}\".",
6
+ "tenantNotFound": "No node tenant found for the decrypted tenant token \"{tenantId}\"."
6
7
  },
7
8
  "tenantAdminService": {
8
9
  "apiKeyAlreadyInUse": "The provided API key is already in use by another tenant.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/api-tenant-processor",
3
- "version": "0.0.3-next.27",
3
+ "version": "0.0.3-next.29",
4
4
  "description": "Tenant resolution services and route handlers that derive tenant context from API keys.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,12 +14,13 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/api-models": "0.0.3-next.27",
17
+ "@twin.org/api-models": "0.0.3-next.29",
18
18
  "@twin.org/context": "next",
19
19
  "@twin.org/core": "next",
20
20
  "@twin.org/entity": "next",
21
21
  "@twin.org/entity-storage-models": "next",
22
22
  "@twin.org/nameof": "next",
23
+ "@twin.org/vault-models": "next",
23
24
  "@twin.org/web": "next"
24
25
  },
25
26
  "main": "./dist/es/index.js",