@twin.org/api-tenant-processor 0.0.3-next.15 → 0.0.3-next.16

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.
@@ -21,6 +21,14 @@ let Tenant = class Tenant {
21
21
  * The date the tenant was created.
22
22
  */
23
23
  dateCreated;
24
+ /**
25
+ * The origin available to the public for accessing the API.
26
+ */
27
+ publicOrigin;
28
+ /**
29
+ * Indicates whether the tenant is the node tenant.
30
+ */
31
+ isNodeTenant;
24
32
  };
25
33
  __decorate([
26
34
  property({ type: "string", isPrimary: true }),
@@ -38,6 +46,14 @@ __decorate([
38
46
  property({ type: "string" }),
39
47
  __metadata("design:type", String)
40
48
  ], Tenant.prototype, "dateCreated", void 0);
49
+ __decorate([
50
+ property({ type: "string", optional: true }),
51
+ __metadata("design:type", String)
52
+ ], Tenant.prototype, "publicOrigin", void 0);
53
+ __decorate([
54
+ property({ type: "boolean" }),
55
+ __metadata("design:type", Boolean)
56
+ ], Tenant.prototype, "isNodeTenant", void 0);
41
57
  Tenant = __decorate([
42
58
  entity()
43
59
  ], Tenant);
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../../src/entities/tenant.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAM;IAClB;;OAEG;IAEI,EAAE,CAAU;IAEnB;;OAEG;IAEI,MAAM,CAAU;IAEvB;;OAEG;IAEI,KAAK,CAAU;IAEtB;;OAEG;IAEI,WAAW,CAAU;CAC5B,CAAA;AAnBO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;kCAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;sCACN;AAMhB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;qCACP;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;2CACD;AAvBhB,MAAM;IADlB,MAAM,EAAE;GACI,MAAM,CAwBlB","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@twin.org/entity\";\n\n/**\n * Class defining the storage for node tenants.\n */\n@entity()\nexport class Tenant {\n\t/**\n\t * The unique identifier for the tenant.\n\t */\n\t@property({ type: \"string\", isPrimary: true })\n\tpublic id!: string;\n\n\t/**\n\t * The api key for the tenant.\n\t */\n\t@property({ type: \"string\" })\n\tpublic apiKey!: string;\n\n\t/**\n\t * The label of the tenant.\n\t */\n\t@property({ type: \"string\" })\n\tpublic label!: string;\n\n\t/**\n\t * The date the tenant was created.\n\t */\n\t@property({ type: \"string\" })\n\tpublic dateCreated!: string;\n}\n"]}
1
+ {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../../src/entities/tenant.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAM;IAClB;;OAEG;IAEI,EAAE,CAAU;IAEnB;;OAEG;IAEI,MAAM,CAAU;IAEvB;;OAEG;IAEI,KAAK,CAAU;IAEtB;;OAEG;IAEI,WAAW,CAAU;IAE5B;;OAEG;IAEI,YAAY,CAAU;IAE7B;;OAEG;IAEI,YAAY,CAAW;CAC9B,CAAA;AA/BO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;kCAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;sCACN;AAMhB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;qCACP;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;2CACD;AAMrB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;4CAChB;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;4CACA;AAnClB,MAAM;IADlB,MAAM,EAAE;GACI,MAAM,CAoClB","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@twin.org/entity\";\n\n/**\n * Class defining the storage for node tenants.\n */\n@entity()\nexport class Tenant {\n\t/**\n\t * The unique identifier for the tenant.\n\t */\n\t@property({ type: \"string\", isPrimary: true })\n\tpublic id!: string;\n\n\t/**\n\t * The api key for the tenant.\n\t */\n\t@property({ type: \"string\" })\n\tpublic apiKey!: string;\n\n\t/**\n\t * The label of the tenant.\n\t */\n\t@property({ type: \"string\" })\n\tpublic label!: string;\n\n\t/**\n\t * The date the tenant was created.\n\t */\n\t@property({ type: \"string\" })\n\tpublic dateCreated!: string;\n\n\t/**\n\t * The origin available to the public for accessing the API.\n\t */\n\t@property({ type: \"string\", optional: true })\n\tpublic publicOrigin?: string;\n\n\t/**\n\t * Indicates whether the tenant is the node tenant.\n\t */\n\t@property({ type: \"boolean\" })\n\tpublic isNodeTenant!: boolean;\n}\n"]}
package/dist/es/index.js CHANGED
@@ -1,8 +1,6 @@
1
1
  // Copyright 2025 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
3
  export * from "./entities/tenant.js";
4
- export * from "./models/ITenant.js";
5
- export * from "./models/ITenantAdminComponent.js";
6
4
  export * from "./models/ITenantAdminServiceConfig.js";
7
5
  export * from "./models/ITenantAdminServiceConstructorOptions.js";
8
6
  export * from "./models/ITenantProcessorConfig.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,mDAAmD,CAAC;AAClE,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./entities/tenant.js\";\nexport * from \"./models/ITenant.js\";\nexport * from \"./models/ITenantAdminComponent.js\";\nexport * from \"./models/ITenantAdminServiceConfig.js\";\nexport * from \"./models/ITenantAdminServiceConstructorOptions.js\";\nexport * from \"./models/ITenantProcessorConfig.js\";\nexport * from \"./models/ITenantProcessorConstructorOptions.js\";\nexport * from \"./schema.js\";\nexport * from \"./tenantAdminService.js\";\nexport * from \"./tenantIdContextIdHandler.js\";\nexport * from \"./tenantProcessor.js\";\nexport * from \"./utils/tenantIdHelper.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uCAAuC,CAAC;AACtD,cAAc,mDAAmD,CAAC;AAClE,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./entities/tenant.js\";\nexport * from \"./models/ITenantAdminServiceConfig.js\";\nexport * from \"./models/ITenantAdminServiceConstructorOptions.js\";\nexport * from \"./models/ITenantProcessorConfig.js\";\nexport * from \"./models/ITenantProcessorConstructorOptions.js\";\nexport * from \"./schema.js\";\nexport * from \"./tenantAdminService.js\";\nexport * from \"./tenantIdContextIdHandler.js\";\nexport * from \"./tenantProcessor.js\";\nexport * from \"./utils/tenantIdHelper.js\";\n"]}
@@ -1,6 +1,5 @@
1
- // Copyright 2024 IOTA Stiftung.
2
- // SPDX-License-Identifier: Apache-2.0.
3
- import { GeneralError, Guards } from "@twin.org/core";
1
+ import { GeneralError, Guards, Is, Url } from "@twin.org/core";
2
+ import { ComparisonOperator } from "@twin.org/entity";
4
3
  import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
5
4
  import { Tenant } from "./entities/tenant.js";
6
5
  /**
@@ -58,6 +57,20 @@ export class TenantAdminService {
58
57
  catch { }
59
58
  return tenant;
60
59
  }
60
+ /**
61
+ * Get a tenant by its public origin.
62
+ * @param publicOrigin The public origin of the tenant.
63
+ * @returns The tenant or undefined if not found.
64
+ */
65
+ async getByPublicOrigin(publicOrigin) {
66
+ Guards.stringValue(TenantAdminService.CLASS_NAME, "publicOrigin", publicOrigin);
67
+ let tenant;
68
+ try {
69
+ tenant = await this._entityStorageConnector.get(publicOrigin, "publicOrigin");
70
+ }
71
+ catch { }
72
+ return tenant;
73
+ }
61
74
  /**
62
75
  * Set a tenant.
63
76
  * @param tenant The tenant to store.
@@ -67,6 +80,13 @@ export class TenantAdminService {
67
80
  Guards.objectValue(TenantAdminService.CLASS_NAME, "tenant", tenant);
68
81
  Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.id", tenant.id, 32);
69
82
  Guards.stringHexLength(TenantAdminService.CLASS_NAME, "tenant.apiKey", tenant.apiKey, 32);
83
+ let publicOrigin;
84
+ if (Is.stringValue(tenant.publicOrigin)) {
85
+ Url.guard(TenantAdminService.CLASS_NAME, "tenant.publicOrigin", tenant.publicOrigin);
86
+ const url = new Url(tenant.publicOrigin);
87
+ const parts = url.parts();
88
+ publicOrigin = `${parts.schema}://${parts.host}${Is.integer(parts.port) ? `:${parts.port}` : ""}`;
89
+ }
70
90
  const existingApiKey = await this.getByApiKey(tenant.apiKey);
71
91
  if (existingApiKey && existingApiKey.id !== tenant.id) {
72
92
  throw new GeneralError(TenantAdminService.CLASS_NAME, "apiKeyAlreadyInUse");
@@ -76,6 +96,9 @@ export class TenantAdminService {
76
96
  tenantEntity.apiKey = tenant.apiKey;
77
97
  tenantEntity.dateCreated = new Date(Date.now()).toISOString();
78
98
  tenantEntity.label = tenant.label;
99
+ tenantEntity.dateCreated = new Date(Date.now()).toISOString();
100
+ tenantEntity.publicOrigin = publicOrigin;
101
+ tenantEntity.isNodeTenant = tenant.isNodeTenant;
79
102
  await this._entityStorageConnector.set(tenantEntity);
80
103
  }
81
104
  /**
@@ -89,12 +112,22 @@ export class TenantAdminService {
89
112
  }
90
113
  /**
91
114
  * Query tenants with pagination.
115
+ * @param options Optional query options.
116
+ * @param options.isNodeTenant Whether to filter for node admin tenants.
92
117
  * @param cursor The cursor to start from.
93
118
  * @param limit The maximum number of tenants to return.
94
119
  * @returns The tenants and the next cursor if more tenants are available.
95
120
  */
96
- async query(cursor, limit) {
97
- const result = await this._entityStorageConnector.query(undefined, undefined, undefined, cursor, limit);
121
+ async query(options, cursor, limit) {
122
+ const conditions = [];
123
+ if (Is.boolean(options?.isNodeTenant)) {
124
+ conditions.push({
125
+ property: "isNodeTenant",
126
+ value: options.isNodeTenant,
127
+ comparison: ComparisonOperator.Equals
128
+ });
129
+ }
130
+ const result = await this._entityStorageConnector.query(conditions.length > 0 ? { conditions } : undefined, undefined, undefined, cursor, limit);
98
131
  return {
99
132
  tenants: result.entities,
100
133
  cursor: result.cursor
@@ -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 { GeneralError, Guards } from \"@twin.org/core\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { Tenant } from \"./entities/tenant.js\";\nimport type { ITenant } from \"./models/ITenant.js\";\nimport type { ITenantAdminComponent } from \"./models/ITenantAdminComponent.js\";\nimport type { ITenantAdminServiceConstructorOptions } from \"./models/ITenantAdminServiceConstructorOptions.js\";\n\n/**\n * Service for performing email messaging operations to a connector.\n */\nexport class TenantAdminService implements ITenantAdminComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TenantAdminService>();\n\n\t/**\n\t * Entity storage connector used by the service.\n\t * @internal\n\t */\n\tprivate readonly _entityStorageConnector: IEntityStorageConnector<Tenant>;\n\n\t/**\n\t * Create a new instance of TenantAdminService.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options?: ITenantAdminServiceConstructorOptions) {\n\t\tthis._entityStorageConnector = EntityStorageConnectorFactory.get(\n\t\t\toptions?.tenantEntityStorageType ?? \"tenant\"\n\t\t);\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TenantAdminService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async get(tenantId: string): Promise<ITenant | undefined> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(tenantId);\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Get a tenant by its api key.\n\t * @param apiKey The api key of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async getByApiKey(apiKey: string): Promise<ITenant | undefined> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(apiKey), apiKey, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Set a tenant.\n\t * @param tenant The tenant to store.\n\t * @returns Nothing.\n\t */\n\tpublic async set(tenant: ITenant): Promise<void> {\n\t\tGuards.objectValue<ITenant>(TenantAdminService.CLASS_NAME, nameof(tenant), tenant);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.id), tenant.id, 32);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.apiKey), tenant.apiKey, 32);\n\n\t\tconst existingApiKey = await this.getByApiKey(tenant.apiKey);\n\t\tif (existingApiKey && existingApiKey.id !== tenant.id) {\n\t\t\tthrow new GeneralError(TenantAdminService.CLASS_NAME, \"apiKeyAlreadyInUse\");\n\t\t}\n\n\t\tconst tenantEntity = new Tenant();\n\t\ttenantEntity.id = tenant.id;\n\t\ttenantEntity.apiKey = tenant.apiKey;\n\t\ttenantEntity.dateCreated = new Date(Date.now()).toISOString();\n\t\ttenantEntity.label = tenant.label;\n\n\t\tawait this._entityStorageConnector.set(tenantEntity);\n\t}\n\n\t/**\n\t * Remove a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(tenantId: string): Promise<void> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\treturn this._entityStorageConnector.remove(tenantId);\n\t}\n\n\t/**\n\t * Query tenants with pagination.\n\t * @param 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\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ tenants: ITenant[]; cursor?: string }> {\n\t\tconst result = await this._entityStorageConnector.query(\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tcursor,\n\t\t\tlimit\n\t\t);\n\n\t\treturn {\n\t\t\ttenants: result.entities as ITenant[],\n\t\t\tcursor: result.cursor\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"tenantAdminService.js","sourceRoot":"","sources":["../../src/tenantAdminService.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EACN,6BAA6B,EAE7B,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAC9B;;OAEG;IACI,MAAM,CAAU,UAAU,wBAAwC;IAEzE;;;OAGG;IACc,uBAAuB,CAAkC;IAE1E;;;OAGG;IACH,YAAY,OAA+C;QAC1D,IAAI,CAAC,uBAAuB,GAAG,6BAA6B,CAAC,GAAG,CAC/D,OAAO,EAAE,uBAAuB,IAAI,QAAQ,CAC5C,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,kBAAkB,CAAC,UAAU,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,GAAG,CAAC,QAAgB;QAChC,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,UAAU,cAAoB,QAAQ,EAAE,EAAE,CAAC,CAAC;QAEtF,IAAI,MAAM,CAAC;QAEX,IAAI,CAAC;YACJ,MAAM,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,OAAO,MAAM,CAAC;IACf,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,WAAW,CAAC,MAAc;QACtC,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,UAAU,YAAkB,MAAM,EAAE,EAAE,CAAC,CAAC;QAElF,IAAI,MAAM,CAAC;QAEX,IAAI,CAAC;YACJ,MAAM,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,OAAO,MAAM,CAAC;IACf,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,iBAAiB,CAAC,YAAoB;QAClD,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,UAAU,kBAAwB,YAAY,CAAC,CAAC;QAEtF,IAAI,MAAM,CAAC;QAEX,IAAI,CAAC;YACJ,MAAM,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QAC/E,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,OAAO,MAAM,CAAC;IACf,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,GAAG,CAAC,MAAe;QAC/B,MAAM,CAAC,WAAW,CAAU,kBAAkB,CAAC,UAAU,YAAkB,MAAM,CAAC,CAAC;QACnF,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,UAAU,eAAqB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACxF,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,UAAU,mBAAyB,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAEhG,IAAI,YAAgC,CAAC;QACrC,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,UAAU,yBAA+B,MAAM,CAAC,YAAY,CAAC,CAAC;YAE3F,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;YAC1B,YAAY,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACnG,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC7D,IAAI,cAAc,IAAI,cAAc,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;YACvD,MAAM,IAAI,YAAY,CAAC,kBAAkB,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,MAAM,EAAE,CAAC;QAClC,YAAY,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;QAC5B,YAAY,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QACpC,YAAY,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9D,YAAY,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAClC,YAAY,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9D,YAAY,CAAC,YAAY,GAAG,YAAY,CAAC;QACzC,YAAY,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QAEhD,MAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACtD,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,MAAM,CAAC,QAAgB;QACnC,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,UAAU,cAAoB,QAAQ,EAAE,EAAE,CAAC,CAAC;QAEtF,OAAO,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,KAAK,CACjB,OAAoC,EACpC,MAAe,EACf,KAAc;QAEd,MAAM,UAAU,GAAG,EAAE,CAAC;QAEtB,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,CAAC;YACvC,UAAU,CAAC,IAAI,CAAC;gBACf,QAAQ,EAAE,cAAc;gBACxB,KAAK,EAAE,OAAO,CAAC,YAAY;gBAC3B,UAAU,EAAE,kBAAkB,CAAC,MAAM;aACrC,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,KAAK,CACtD,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,SAAS,EAClD,SAAS,EACT,SAAS,EACT,MAAM,EACN,KAAK,CACL,CAAC;QAEF,OAAO;YACN,OAAO,EAAE,MAAM,CAAC,QAAqB;YACrC,MAAM,EAAE,MAAM,CAAC,MAAM;SACrB,CAAC;IACH,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITenantAdminComponent, ITenant } from \"@twin.org/api-models\";\nimport { GeneralError, Guards, Is, Url } from \"@twin.org/core\";\nimport { ComparisonOperator } from \"@twin.org/entity\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { Tenant } from \"./entities/tenant.js\";\nimport type { ITenantAdminServiceConstructorOptions } from \"./models/ITenantAdminServiceConstructorOptions.js\";\n\n/**\n * Service for performing email messaging operations to a connector.\n */\nexport class TenantAdminService implements ITenantAdminComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TenantAdminService>();\n\n\t/**\n\t * Entity storage connector used by the service.\n\t * @internal\n\t */\n\tprivate readonly _entityStorageConnector: IEntityStorageConnector<Tenant>;\n\n\t/**\n\t * Create a new instance of TenantAdminService.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options?: ITenantAdminServiceConstructorOptions) {\n\t\tthis._entityStorageConnector = EntityStorageConnectorFactory.get(\n\t\t\toptions?.tenantEntityStorageType ?? \"tenant\"\n\t\t);\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TenantAdminService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async get(tenantId: string): Promise<ITenant | undefined> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(tenantId);\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Get a tenant by its api key.\n\t * @param apiKey The api key of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async getByApiKey(apiKey: string): Promise<ITenant | undefined> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(apiKey), apiKey, 32);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(apiKey, \"apiKey\");\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Get a tenant by its public origin.\n\t * @param publicOrigin The public origin of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tpublic async getByPublicOrigin(publicOrigin: string): Promise<ITenant | undefined> {\n\t\tGuards.stringValue(TenantAdminService.CLASS_NAME, nameof(publicOrigin), publicOrigin);\n\n\t\tlet tenant;\n\n\t\ttry {\n\t\t\ttenant = await this._entityStorageConnector.get(publicOrigin, \"publicOrigin\");\n\t\t} catch {}\n\n\t\treturn tenant;\n\t}\n\n\t/**\n\t * Set a tenant.\n\t * @param tenant The tenant to store.\n\t * @returns Nothing.\n\t */\n\tpublic async set(tenant: ITenant): Promise<void> {\n\t\tGuards.objectValue<ITenant>(TenantAdminService.CLASS_NAME, nameof(tenant), tenant);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.id), tenant.id, 32);\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenant.apiKey), tenant.apiKey, 32);\n\n\t\tlet publicOrigin: string | undefined;\n\t\tif (Is.stringValue(tenant.publicOrigin)) {\n\t\t\tUrl.guard(TenantAdminService.CLASS_NAME, nameof(tenant.publicOrigin), tenant.publicOrigin);\n\n\t\t\tconst url = new Url(tenant.publicOrigin);\n\t\t\tconst parts = url.parts();\n\t\t\tpublicOrigin = `${parts.schema}://${parts.host}${Is.integer(parts.port) ? `:${parts.port}` : \"\"}`;\n\t\t}\n\n\t\tconst existingApiKey = await this.getByApiKey(tenant.apiKey);\n\t\tif (existingApiKey && existingApiKey.id !== tenant.id) {\n\t\t\tthrow new GeneralError(TenantAdminService.CLASS_NAME, \"apiKeyAlreadyInUse\");\n\t\t}\n\n\t\tconst tenantEntity = new Tenant();\n\t\ttenantEntity.id = tenant.id;\n\t\ttenantEntity.apiKey = tenant.apiKey;\n\t\ttenantEntity.dateCreated = new Date(Date.now()).toISOString();\n\t\ttenantEntity.label = tenant.label;\n\t\ttenantEntity.dateCreated = new Date(Date.now()).toISOString();\n\t\ttenantEntity.publicOrigin = publicOrigin;\n\t\ttenantEntity.isNodeTenant = tenant.isNodeTenant;\n\n\t\tawait this._entityStorageConnector.set(tenantEntity);\n\t}\n\n\t/**\n\t * Remove a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(tenantId: string): Promise<void> {\n\t\tGuards.stringHexLength(TenantAdminService.CLASS_NAME, nameof(tenantId), tenantId, 32);\n\n\t\treturn this._entityStorageConnector.remove(tenantId);\n\t}\n\n\t/**\n\t * Query tenants with pagination.\n\t * @param options Optional query options.\n\t * @param options.isNodeTenant Whether to filter for node admin tenants.\n\t * @param cursor The cursor to start from.\n\t * @param limit The maximum number of tenants to return.\n\t * @returns The tenants and the next cursor if more tenants are available.\n\t */\n\tpublic async query(\n\t\toptions?: { isNodeTenant?: boolean },\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ tenants: ITenant[]; cursor?: string }> {\n\t\tconst conditions = [];\n\n\t\tif (Is.boolean(options?.isNodeTenant)) {\n\t\t\tconditions.push({\n\t\t\t\tproperty: \"isNodeTenant\",\n\t\t\t\tvalue: options.isNodeTenant,\n\t\t\t\tcomparison: ComparisonOperator.Equals\n\t\t\t});\n\t\t}\n\n\t\tconst result = await this._entityStorageConnector.query(\n\t\t\tconditions.length > 0 ? { conditions } : undefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tcursor,\n\t\t\tlimit\n\t\t);\n\n\t\treturn {\n\t\t\ttenants: result.entities as ITenant[],\n\t\t\tcursor: result.cursor\n\t\t};\n\t}\n}\n"]}
@@ -65,6 +65,9 @@ export class TenantProcessor {
65
65
  }
66
66
  else {
67
67
  contextIds[ContextIdKeys.Tenant] = nodeTenant.id;
68
+ if (Is.stringValue(nodeTenant.publicOrigin)) {
69
+ processorState.publicOrigin = nodeTenant.publicOrigin;
70
+ }
68
71
  }
69
72
  }
70
73
  catch (err) {
@@ -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;oBAClD,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}\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":"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,6 +1,6 @@
1
1
  // Copyright 2025 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
- import { Converter, RandomHelper } from "@twin.org/core";
3
+ import { RandomHelper } from "@twin.org/core";
4
4
  /**
5
5
  * Helper class for tenant id related operations.
6
6
  */
@@ -10,14 +10,14 @@ export class TenantIdHelper {
10
10
  * @returns A new tenant ID.
11
11
  */
12
12
  static generateTenantId() {
13
- return Converter.bytesToHex(RandomHelper.generate(16));
13
+ return RandomHelper.generateUuidV7("compact");
14
14
  }
15
15
  /**
16
16
  * Generates a new API Key.
17
17
  * @returns A new API Key.
18
18
  */
19
19
  static generateApiKey() {
20
- return Converter.bytesToHex(RandomHelper.generate(16));
20
+ return RandomHelper.generateUuidV7("compact");
21
21
  }
22
22
  }
23
23
  //# sourceMappingURL=tenantIdHelper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tenantIdHelper.js","sourceRoot":"","sources":["../../../src/utils/tenantIdHelper.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEzD;;GAEG;AACH,MAAM,OAAO,cAAc;IAC1B;;;OAGG;IACI,MAAM,CAAC,gBAAgB;QAC7B,OAAO,SAAS,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,cAAc;QAC3B,OAAO,SAAS,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;CACD","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Converter, RandomHelper } from \"@twin.org/core\";\n\n/**\n * Helper class for tenant id related operations.\n */\nexport class TenantIdHelper {\n\t/**\n\t * Generates a new tenant ID.\n\t * @returns A new tenant ID.\n\t */\n\tpublic static generateTenantId(): string {\n\t\treturn Converter.bytesToHex(RandomHelper.generate(16));\n\t}\n\n\t/**\n\t * Generates a new API Key.\n\t * @returns A new API Key.\n\t */\n\tpublic static generateApiKey(): string {\n\t\treturn Converter.bytesToHex(RandomHelper.generate(16));\n\t}\n}\n"]}
1
+ {"version":3,"file":"tenantIdHelper.js","sourceRoot":"","sources":["../../../src/utils/tenantIdHelper.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACH,MAAM,OAAO,cAAc;IAC1B;;;OAGG;IACI,MAAM,CAAC,gBAAgB;QAC7B,OAAO,YAAY,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,cAAc;QAC3B,OAAO,YAAY,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;CACD","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { RandomHelper } from \"@twin.org/core\";\n\n/**\n * Helper class for tenant id related operations.\n */\nexport class TenantIdHelper {\n\t/**\n\t * Generates a new tenant ID.\n\t * @returns A new tenant ID.\n\t */\n\tpublic static generateTenantId(): string {\n\t\treturn RandomHelper.generateUuidV7(\"compact\");\n\t}\n\n\t/**\n\t * Generates a new API Key.\n\t * @returns A new API Key.\n\t */\n\tpublic static generateApiKey(): string {\n\t\treturn RandomHelper.generateUuidV7(\"compact\");\n\t}\n}\n"]}
@@ -18,4 +18,12 @@ export declare class Tenant {
18
18
  * The date the tenant was created.
19
19
  */
20
20
  dateCreated: string;
21
+ /**
22
+ * The origin available to the public for accessing the API.
23
+ */
24
+ publicOrigin?: string;
25
+ /**
26
+ * Indicates whether the tenant is the node tenant.
27
+ */
28
+ isNodeTenant: boolean;
21
29
  }
@@ -1,6 +1,4 @@
1
1
  export * from "./entities/tenant.js";
2
- export * from "./models/ITenant.js";
3
- export * from "./models/ITenantAdminComponent.js";
4
2
  export * from "./models/ITenantAdminServiceConfig.js";
5
3
  export * from "./models/ITenantAdminServiceConstructorOptions.js";
6
4
  export * from "./models/ITenantProcessorConfig.js";
@@ -1,5 +1,4 @@
1
- import type { ITenant } from "./models/ITenant.js";
2
- import type { ITenantAdminComponent } from "./models/ITenantAdminComponent.js";
1
+ import type { ITenantAdminComponent, ITenant } from "@twin.org/api-models";
3
2
  import type { ITenantAdminServiceConstructorOptions } from "./models/ITenantAdminServiceConstructorOptions.js";
4
3
  /**
5
4
  * Service for performing email messaging operations to a connector.
@@ -31,6 +30,12 @@ export declare class TenantAdminService implements ITenantAdminComponent {
31
30
  * @returns The tenant or undefined if not found.
32
31
  */
33
32
  getByApiKey(apiKey: string): Promise<ITenant | undefined>;
33
+ /**
34
+ * Get a tenant by its public origin.
35
+ * @param publicOrigin The public origin of the tenant.
36
+ * @returns The tenant or undefined if not found.
37
+ */
38
+ getByPublicOrigin(publicOrigin: string): Promise<ITenant | undefined>;
34
39
  /**
35
40
  * Set a tenant.
36
41
  * @param tenant The tenant to store.
@@ -45,11 +50,15 @@ export declare class TenantAdminService implements ITenantAdminComponent {
45
50
  remove(tenantId: string): Promise<void>;
46
51
  /**
47
52
  * Query tenants with pagination.
53
+ * @param options Optional query options.
54
+ * @param options.isNodeTenant Whether to filter for node admin tenants.
48
55
  * @param cursor The cursor to start from.
49
56
  * @param limit The maximum number of tenants to return.
50
57
  * @returns The tenants and the next cursor if more tenants are available.
51
58
  */
52
- query(cursor?: string, limit?: number): Promise<{
59
+ query(options?: {
60
+ isNodeTenant?: boolean;
61
+ }, cursor?: string, limit?: number): Promise<{
53
62
  tenants: ITenant[];
54
63
  cursor?: string;
55
64
  }>;
package/docs/changelog.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [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)
4
+
5
+
6
+ ### Features
7
+
8
+ * public base url ([#70](https://github.com/twinfoundation/api/issues/70)) ([5b958cd](https://github.com/twinfoundation/api/commit/5b958cd91e8a38cdae2835ff5f2356c7e48d37c3))
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.15 to 0.0.3-next.16
16
+
3
17
  ## [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)
4
18
 
5
19
 
@@ -43,3 +43,19 @@ The label of the tenant.
43
43
  > **dateCreated**: `string`
44
44
 
45
45
  The date the tenant was created.
46
+
47
+ ***
48
+
49
+ ### publicOrigin?
50
+
51
+ > `optional` **publicOrigin**: `string`
52
+
53
+ The origin available to the public for accessing the API.
54
+
55
+ ***
56
+
57
+ ### isNodeTenant
58
+
59
+ > **isNodeTenant**: `boolean`
60
+
61
+ Indicates whether the tenant is the node tenant.
@@ -4,7 +4,7 @@ Service for performing email messaging operations to a connector.
4
4
 
5
5
  ## Implements
6
6
 
7
- - [`ITenantAdminComponent`](../interfaces/ITenantAdminComponent.md)
7
+ - `ITenantAdminComponent`
8
8
 
9
9
  ## Constructors
10
10
 
@@ -56,7 +56,7 @@ The class name of the component.
56
56
 
57
57
  ### get()
58
58
 
59
- > **get**(`tenantId`): `Promise`\<[`ITenant`](../interfaces/ITenant.md) \| `undefined`\>
59
+ > **get**(`tenantId`): `Promise`\<`ITenant` \| `undefined`\>
60
60
 
61
61
  Get a tenant by its id.
62
62
 
@@ -70,19 +70,19 @@ The id of the tenant.
70
70
 
71
71
  #### Returns
72
72
 
73
- `Promise`\<[`ITenant`](../interfaces/ITenant.md) \| `undefined`\>
73
+ `Promise`\<`ITenant` \| `undefined`\>
74
74
 
75
75
  The tenant or undefined if not found.
76
76
 
77
77
  #### Implementation of
78
78
 
79
- [`ITenantAdminComponent`](../interfaces/ITenantAdminComponent.md).[`get`](../interfaces/ITenantAdminComponent.md#get)
79
+ `ITenantAdminComponent.get`
80
80
 
81
81
  ***
82
82
 
83
83
  ### getByApiKey()
84
84
 
85
- > **getByApiKey**(`apiKey`): `Promise`\<[`ITenant`](../interfaces/ITenant.md) \| `undefined`\>
85
+ > **getByApiKey**(`apiKey`): `Promise`\<`ITenant` \| `undefined`\>
86
86
 
87
87
  Get a tenant by its api key.
88
88
 
@@ -96,13 +96,39 @@ The api key of the tenant.
96
96
 
97
97
  #### Returns
98
98
 
99
- `Promise`\<[`ITenant`](../interfaces/ITenant.md) \| `undefined`\>
99
+ `Promise`\<`ITenant` \| `undefined`\>
100
100
 
101
101
  The tenant or undefined if not found.
102
102
 
103
103
  #### Implementation of
104
104
 
105
- [`ITenantAdminComponent`](../interfaces/ITenantAdminComponent.md).[`getByApiKey`](../interfaces/ITenantAdminComponent.md#getbyapikey)
105
+ `ITenantAdminComponent.getByApiKey`
106
+
107
+ ***
108
+
109
+ ### getByPublicOrigin()
110
+
111
+ > **getByPublicOrigin**(`publicOrigin`): `Promise`\<`ITenant` \| `undefined`\>
112
+
113
+ Get a tenant by its public origin.
114
+
115
+ #### Parameters
116
+
117
+ ##### publicOrigin
118
+
119
+ `string`
120
+
121
+ The public origin of the tenant.
122
+
123
+ #### Returns
124
+
125
+ `Promise`\<`ITenant` \| `undefined`\>
126
+
127
+ The tenant or undefined if not found.
128
+
129
+ #### Implementation of
130
+
131
+ `ITenantAdminComponent.getByPublicOrigin`
106
132
 
107
133
  ***
108
134
 
@@ -116,7 +142,7 @@ Set a tenant.
116
142
 
117
143
  ##### tenant
118
144
 
119
- [`ITenant`](../interfaces/ITenant.md)
145
+ `ITenant`
120
146
 
121
147
  The tenant to store.
122
148
 
@@ -128,7 +154,7 @@ Nothing.
128
154
 
129
155
  #### Implementation of
130
156
 
131
- [`ITenantAdminComponent`](../interfaces/ITenantAdminComponent.md).[`set`](../interfaces/ITenantAdminComponent.md#set)
157
+ `ITenantAdminComponent.set`
132
158
 
133
159
  ***
134
160
 
@@ -154,18 +180,28 @@ Nothing.
154
180
 
155
181
  #### Implementation of
156
182
 
157
- [`ITenantAdminComponent`](../interfaces/ITenantAdminComponent.md).[`remove`](../interfaces/ITenantAdminComponent.md#remove)
183
+ `ITenantAdminComponent.remove`
158
184
 
159
185
  ***
160
186
 
161
187
  ### query()
162
188
 
163
- > **query**(`cursor?`, `limit?`): `Promise`\<\{ `tenants`: [`ITenant`](../interfaces/ITenant.md)[]; `cursor?`: `string`; \}\>
189
+ > **query**(`options?`, `cursor?`, `limit?`): `Promise`\<\{ `tenants`: `ITenant`[]; `cursor?`: `string`; \}\>
164
190
 
165
191
  Query tenants with pagination.
166
192
 
167
193
  #### Parameters
168
194
 
195
+ ##### options?
196
+
197
+ Optional query options.
198
+
199
+ ###### isNodeTenant?
200
+
201
+ `boolean`
202
+
203
+ Whether to filter for node admin tenants.
204
+
169
205
  ##### cursor?
170
206
 
171
207
  `string`
@@ -180,10 +216,10 @@ The maximum number of tenants to return.
180
216
 
181
217
  #### Returns
182
218
 
183
- `Promise`\<\{ `tenants`: [`ITenant`](../interfaces/ITenant.md)[]; `cursor?`: `string`; \}\>
219
+ `Promise`\<\{ `tenants`: `ITenant`[]; `cursor?`: `string`; \}\>
184
220
 
185
221
  The tenants and the next cursor if more tenants are available.
186
222
 
187
223
  #### Implementation of
188
224
 
189
- [`ITenantAdminComponent`](../interfaces/ITenantAdminComponent.md).[`query`](../interfaces/ITenantAdminComponent.md#query)
225
+ `ITenantAdminComponent.query`
@@ -10,8 +10,6 @@
10
10
 
11
11
  ## Interfaces
12
12
 
13
- - [ITenant](interfaces/ITenant.md)
14
- - [ITenantAdminComponent](interfaces/ITenantAdminComponent.md)
15
13
  - [ITenantAdminServiceConfig](interfaces/ITenantAdminServiceConfig.md)
16
14
  - [ITenantAdminServiceConstructorOptions](interfaces/ITenantAdminServiceConstructorOptions.md)
17
15
  - [ITenantProcessorConfig](interfaces/ITenantProcessorConfig.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/api-tenant-processor",
3
- "version": "0.0.3-next.15",
3
+ "version": "0.0.3-next.16",
4
4
  "description": "API Tenant Processor for converting and api key to a tenant id.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/api-models": "0.0.3-next.15",
17
+ "@twin.org/api-models": "0.0.3-next.16",
18
18
  "@twin.org/context": "next",
19
19
  "@twin.org/core": "next",
20
20
  "@twin.org/entity": "next",
@@ -1,4 +0,0 @@
1
- // Copyright 2025 IOTA Stiftung.
2
- // SPDX-License-Identifier: Apache-2.0.
3
- export {};
4
- //# sourceMappingURL=ITenant.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ITenant.js","sourceRoot":"","sources":["../../../src/models/ITenant.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Model defining the tenant.\n */\nexport interface ITenant {\n\t/**\n\t * The unique identifier for the tenant.\n\t */\n\tid: string;\n\n\t/**\n\t * The api key for the tenant.\n\t */\n\tapiKey: string;\n\n\t/**\n\t * The label of the tenant.\n\t */\n\tlabel: string;\n\n\t/**\n\t * The date the tenant was created.\n\t */\n\tdateCreated: string;\n}\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ITenantAdminComponent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ITenantAdminComponent.js","sourceRoot":"","sources":["../../../src/models/ITenantAdminComponent.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IComponent } from \"@twin.org/core\";\nimport type { ITenant } from \"./ITenant.js\";\n\n/**\n * Configuration for the tenant admin component\n */\nexport interface ITenantAdminComponent extends IComponent {\n\t/**\n\t * Get a tenant by its id.\n\t * @param tenantId The id of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tget(tenantId: string): Promise<ITenant | undefined>;\n\n\t/**\n\t * Get a tenant by its api key.\n\t * @param apiKey The api key of the tenant.\n\t * @returns The tenant or undefined if not found.\n\t */\n\tgetByApiKey(apiKey: string): Promise<ITenant | undefined>;\n\n\t/**\n\t * Set a tenant.\n\t * @param tenant The tenant to store.\n\t * @returns Nothing.\n\t */\n\tset(tenant: ITenant): Promise<void>;\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\tremove(tenantId: string): Promise<void>;\n\n\t/**\n\t * Query tenants with pagination.\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\tquery(cursor?: string, limit?: number): Promise<{ tenants: ITenant[]; cursor?: string }>;\n}\n"]}
@@ -1,21 +0,0 @@
1
- /**
2
- * Model defining the tenant.
3
- */
4
- export interface ITenant {
5
- /**
6
- * The unique identifier for the tenant.
7
- */
8
- id: string;
9
- /**
10
- * The api key for the tenant.
11
- */
12
- apiKey: string;
13
- /**
14
- * The label of the tenant.
15
- */
16
- label: string;
17
- /**
18
- * The date the tenant was created.
19
- */
20
- dateCreated: string;
21
- }
@@ -1,41 +0,0 @@
1
- import type { IComponent } from "@twin.org/core";
2
- import type { ITenant } from "./ITenant.js";
3
- /**
4
- * Configuration for the tenant admin component
5
- */
6
- export interface ITenantAdminComponent extends IComponent {
7
- /**
8
- * Get a tenant by its id.
9
- * @param tenantId The id of the tenant.
10
- * @returns The tenant or undefined if not found.
11
- */
12
- get(tenantId: string): Promise<ITenant | undefined>;
13
- /**
14
- * Get a tenant by its api key.
15
- * @param apiKey The api key of the tenant.
16
- * @returns The tenant or undefined if not found.
17
- */
18
- getByApiKey(apiKey: string): Promise<ITenant | undefined>;
19
- /**
20
- * Set a tenant.
21
- * @param tenant The tenant to store.
22
- * @returns Nothing.
23
- */
24
- set(tenant: ITenant): Promise<void>;
25
- /**
26
- * Remove a tenant by its id.
27
- * @param tenantId The id of the tenant.
28
- * @returns Nothing.
29
- */
30
- remove(tenantId: string): Promise<void>;
31
- /**
32
- * Query tenants with pagination.
33
- * @param cursor The cursor to start from.
34
- * @param limit The maximum number of tenants to return.
35
- * @returns The tenants and the next cursor if more tenants are available.
36
- */
37
- query(cursor?: string, limit?: number): Promise<{
38
- tenants: ITenant[];
39
- cursor?: string;
40
- }>;
41
- }
@@ -1,35 +0,0 @@
1
- # Interface: ITenant
2
-
3
- Model defining the tenant.
4
-
5
- ## Properties
6
-
7
- ### id
8
-
9
- > **id**: `string`
10
-
11
- The unique identifier for the tenant.
12
-
13
- ***
14
-
15
- ### apiKey
16
-
17
- > **apiKey**: `string`
18
-
19
- The api key for the tenant.
20
-
21
- ***
22
-
23
- ### label
24
-
25
- > **label**: `string`
26
-
27
- The label of the tenant.
28
-
29
- ***
30
-
31
- ### dateCreated
32
-
33
- > **dateCreated**: `string`
34
-
35
- The date the tenant was created.
@@ -1,123 +0,0 @@
1
- # Interface: ITenantAdminComponent
2
-
3
- Configuration for the tenant admin component
4
-
5
- ## Extends
6
-
7
- - `IComponent`
8
-
9
- ## Methods
10
-
11
- ### get()
12
-
13
- > **get**(`tenantId`): `Promise`\<[`ITenant`](ITenant.md) \| `undefined`\>
14
-
15
- Get a tenant by its id.
16
-
17
- #### Parameters
18
-
19
- ##### tenantId
20
-
21
- `string`
22
-
23
- The id of the tenant.
24
-
25
- #### Returns
26
-
27
- `Promise`\<[`ITenant`](ITenant.md) \| `undefined`\>
28
-
29
- The tenant or undefined if not found.
30
-
31
- ***
32
-
33
- ### getByApiKey()
34
-
35
- > **getByApiKey**(`apiKey`): `Promise`\<[`ITenant`](ITenant.md) \| `undefined`\>
36
-
37
- Get a tenant by its api key.
38
-
39
- #### Parameters
40
-
41
- ##### apiKey
42
-
43
- `string`
44
-
45
- The api key of the tenant.
46
-
47
- #### Returns
48
-
49
- `Promise`\<[`ITenant`](ITenant.md) \| `undefined`\>
50
-
51
- The tenant or undefined if not found.
52
-
53
- ***
54
-
55
- ### set()
56
-
57
- > **set**(`tenant`): `Promise`\<`void`\>
58
-
59
- Set a tenant.
60
-
61
- #### Parameters
62
-
63
- ##### tenant
64
-
65
- [`ITenant`](ITenant.md)
66
-
67
- The tenant to store.
68
-
69
- #### Returns
70
-
71
- `Promise`\<`void`\>
72
-
73
- Nothing.
74
-
75
- ***
76
-
77
- ### remove()
78
-
79
- > **remove**(`tenantId`): `Promise`\<`void`\>
80
-
81
- Remove a tenant by its id.
82
-
83
- #### Parameters
84
-
85
- ##### tenantId
86
-
87
- `string`
88
-
89
- The id of the tenant.
90
-
91
- #### Returns
92
-
93
- `Promise`\<`void`\>
94
-
95
- Nothing.
96
-
97
- ***
98
-
99
- ### query()
100
-
101
- > **query**(`cursor?`, `limit?`): `Promise`\<\{ `tenants`: [`ITenant`](ITenant.md)[]; `cursor?`: `string`; \}\>
102
-
103
- Query tenants with pagination.
104
-
105
- #### Parameters
106
-
107
- ##### cursor?
108
-
109
- `string`
110
-
111
- The cursor to start from.
112
-
113
- ##### limit?
114
-
115
- `number`
116
-
117
- The maximum number of tenants to return.
118
-
119
- #### Returns
120
-
121
- `Promise`\<\{ `tenants`: [`ITenant`](ITenant.md)[]; `cursor?`: `string`; \}\>
122
-
123
- The tenants and the next cursor if more tenants are available.