@zudojs/tenancy 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/context/contextManager.core.d.ts +46 -0
- package/dist/context/contextManager.core.d.ts.map +1 -0
- package/dist/context/contextManager.core.js +76 -0
- package/dist/context/contextManager.core.js.map +1 -0
- package/dist/context/contextStorage.core.d.ts +24 -0
- package/dist/context/contextStorage.core.d.ts.map +1 -0
- package/dist/context/contextStorage.core.js +38 -0
- package/dist/context/contextStorage.core.js.map +1 -0
- package/dist/context/index.d.ts +8 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +8 -0
- package/dist/context/index.js.map +1 -0
- package/dist/http/httpHelpers.d.ts +46 -0
- package/dist/http/httpHelpers.d.ts.map +1 -0
- package/dist/http/httpHelpers.js +40 -0
- package/dist/http/httpHelpers.js.map +1 -0
- package/dist/http/httpTypes.d.ts +39 -0
- package/dist/http/httpTypes.d.ts.map +1 -0
- package/dist/http/httpTypes.js +9 -0
- package/dist/http/httpTypes.js.map +1 -0
- package/dist/http/index.d.ts +12 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +9 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/tenancyMiddleware.core.d.ts +48 -0
- package/dist/http/tenancyMiddleware.core.d.ts.map +1 -0
- package/dist/http/tenancyMiddleware.core.js +93 -0
- package/dist/http/tenancyMiddleware.core.js.map +1 -0
- package/dist/http/tenancyMiddleware.guard.d.ts +27 -0
- package/dist/http/tenancyMiddleware.guard.d.ts.map +1 -0
- package/dist/http/tenancyMiddleware.guard.js +43 -0
- package/dist/http/tenancyMiddleware.guard.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/repository/index.d.ts +8 -0
- package/dist/repository/index.d.ts.map +1 -0
- package/dist/repository/index.js +8 -0
- package/dist/repository/index.js.map +1 -0
- package/dist/repository/repository.core.d.ts +27 -0
- package/dist/repository/repository.core.d.ts.map +1 -0
- package/dist/repository/repository.core.js +65 -0
- package/dist/repository/repository.core.js.map +1 -0
- package/dist/repository/tenantManager.core.d.ts +46 -0
- package/dist/repository/tenantManager.core.d.ts.map +1 -0
- package/dist/repository/tenantManager.core.js +74 -0
- package/dist/repository/tenantManager.core.js.map +1 -0
- package/dist/resolver/index.d.ts +8 -0
- package/dist/resolver/index.d.ts.map +1 -0
- package/dist/resolver/index.js +8 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/resolver/resolverChain.core.d.ts +16 -0
- package/dist/resolver/resolverChain.core.d.ts.map +1 -0
- package/dist/resolver/resolverChain.core.js +48 -0
- package/dist/resolver/resolverChain.core.js.map +1 -0
- package/dist/resolver/resolvers/headerResolver.core.d.ts +21 -0
- package/dist/resolver/resolvers/headerResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/headerResolver.core.js +28 -0
- package/dist/resolver/resolvers/headerResolver.core.js.map +1 -0
- package/dist/resolver/resolvers/index.d.ts +10 -0
- package/dist/resolver/resolvers/index.d.ts.map +1 -0
- package/dist/resolver/resolvers/index.js +10 -0
- package/dist/resolver/resolvers/index.js.map +1 -0
- package/dist/resolver/resolvers/jwtResolver.core.d.ts +27 -0
- package/dist/resolver/resolvers/jwtResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/jwtResolver.core.js +31 -0
- package/dist/resolver/resolvers/jwtResolver.core.js.map +1 -0
- package/dist/resolver/resolvers/pathResolver.core.d.ts +24 -0
- package/dist/resolver/resolvers/pathResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/pathResolver.core.js +41 -0
- package/dist/resolver/resolvers/pathResolver.core.js.map +1 -0
- package/dist/resolver/resolvers/subdomainResolver.core.d.ts +24 -0
- package/dist/resolver/resolvers/subdomainResolver.core.d.ts.map +1 -0
- package/dist/resolver/resolvers/subdomainResolver.core.js +48 -0
- package/dist/resolver/resolvers/subdomainResolver.core.js.map +1 -0
- package/dist/security/guard.core.d.ts +33 -0
- package/dist/security/guard.core.d.ts.map +1 -0
- package/dist/security/guard.core.js +64 -0
- package/dist/security/guard.core.js.map +1 -0
- package/dist/security/index.d.ts +7 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +7 -0
- package/dist/security/index.js.map +1 -0
- package/dist/tenancyErrors/index.d.ts +8 -0
- package/dist/tenancyErrors/index.d.ts.map +1 -0
- package/dist/tenancyErrors/index.js +8 -0
- package/dist/tenancyErrors/index.js.map +1 -0
- package/dist/tenancyErrors/tenancyError.base.d.ts +17 -0
- package/dist/tenancyErrors/tenancyError.base.d.ts.map +1 -0
- package/dist/tenancyErrors/tenancyError.base.js +19 -0
- package/dist/tenancyErrors/tenancyError.base.js.map +1 -0
- package/dist/tenancyErrors/tenancyError.types.d.ts +68 -0
- package/dist/tenancyErrors/tenancyError.types.d.ts.map +1 -0
- package/dist/tenancyErrors/tenancyError.types.js +118 -0
- package/dist/tenancyErrors/tenancyError.types.js.map +1 -0
- package/dist/tenancyTypes/index.d.ts +11 -0
- package/dist/tenancyTypes/index.d.ts.map +1 -0
- package/dist/tenancyTypes/index.js +11 -0
- package/dist/tenancyTypes/index.js.map +1 -0
- package/dist/tenancyTypes/repositoryTypes.d.ts +40 -0
- package/dist/tenancyTypes/repositoryTypes.d.ts.map +1 -0
- package/dist/tenancyTypes/repositoryTypes.js +7 -0
- package/dist/tenancyTypes/repositoryTypes.js.map +1 -0
- package/dist/tenancyTypes/resolverTypes.d.ts +34 -0
- package/dist/tenancyTypes/resolverTypes.d.ts.map +1 -0
- package/dist/tenancyTypes/resolverTypes.js +7 -0
- package/dist/tenancyTypes/resolverTypes.js.map +1 -0
- package/dist/tenancyTypes/tenancyOptions.d.ts +37 -0
- package/dist/tenancyTypes/tenancyOptions.d.ts.map +1 -0
- package/dist/tenancyTypes/tenancyOptions.js +7 -0
- package/dist/tenancyTypes/tenancyOptions.js.map +1 -0
- package/dist/tenancyTypes/tenantIdentity.d.ts +21 -0
- package/dist/tenancyTypes/tenantIdentity.d.ts.map +1 -0
- package/dist/tenancyTypes/tenantIdentity.js +13 -0
- package/dist/tenancyTypes/tenantIdentity.js.map +1 -0
- package/dist/tenancyTypes/tenantInterface.d.ts +47 -0
- package/dist/tenancyTypes/tenantInterface.d.ts.map +1 -0
- package/dist/tenancyTypes/tenantInterface.js +7 -0
- package/dist/tenancyTypes/tenantInterface.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/utils.helper.d.ts +24 -0
- package/dist/utils/utils.helper.d.ts.map +1 -0
- package/dist/utils/utils.helper.js +30 -0
- package/dist/utils/utils.helper.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory tenant repository and domain registry.
|
|
3
|
+
*
|
|
4
|
+
* @module repository/repository
|
|
5
|
+
*/
|
|
6
|
+
import { TenantNotFoundError } from "../tenancyErrors/tenancyError.types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create an in-memory tenant repository.
|
|
9
|
+
*/
|
|
10
|
+
export function createMemoryTenantRepository() {
|
|
11
|
+
const tenants = new Map();
|
|
12
|
+
const bySlug = new Map();
|
|
13
|
+
const byDomain = new Map();
|
|
14
|
+
return {
|
|
15
|
+
async findById(id) {
|
|
16
|
+
return tenants.get(id);
|
|
17
|
+
},
|
|
18
|
+
async findBySlug(slug) {
|
|
19
|
+
return bySlug.get(slug);
|
|
20
|
+
},
|
|
21
|
+
async findByDomain(domain) {
|
|
22
|
+
return byDomain.get(domain);
|
|
23
|
+
},
|
|
24
|
+
add(tenant) {
|
|
25
|
+
tenants.set(tenant.id, tenant);
|
|
26
|
+
if (tenant.slug)
|
|
27
|
+
bySlug.set(tenant.slug, tenant);
|
|
28
|
+
},
|
|
29
|
+
remove(id) {
|
|
30
|
+
const tenant = tenants.get(id);
|
|
31
|
+
if (tenant) {
|
|
32
|
+
tenants.delete(id);
|
|
33
|
+
if (tenant.slug)
|
|
34
|
+
bySlug.delete(tenant.slug);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
all() {
|
|
38
|
+
return Array.from(tenants.values());
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a domain-to-tenant registry.
|
|
44
|
+
*/
|
|
45
|
+
export function createDomainRegistry() {
|
|
46
|
+
const domains = new Map();
|
|
47
|
+
return {
|
|
48
|
+
register(domain, tenantId) {
|
|
49
|
+
domains.set(domain, tenantId);
|
|
50
|
+
},
|
|
51
|
+
unregister(domain) {
|
|
52
|
+
domains.delete(domain);
|
|
53
|
+
},
|
|
54
|
+
resolve(domain) {
|
|
55
|
+
return domains.get(domain);
|
|
56
|
+
},
|
|
57
|
+
all() {
|
|
58
|
+
return Array.from(domains.entries()).map(([domain, tenantId]) => ({
|
|
59
|
+
domain,
|
|
60
|
+
tenantId,
|
|
61
|
+
}));
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=repository.core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.core.js","sourceRoot":"","sources":["../../src/repository/repository.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAE7E;;GAEG;AACH,MAAM,UAAU,4BAA4B;IAK1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE3C,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,EAAY;YACzB,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,IAAY;YAC3B,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,MAAc;YAC/B,OAAO,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAED,GAAG,CAAC,MAAc;YAChB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAC/B,IAAI,MAAM,CAAC,IAAI;gBAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,CAAC,EAAY;YACjB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/B,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACnB,IAAI,MAAM,CAAC,IAAI;oBAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QAED,GAAG;YACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE5C,OAAO;QACL,QAAQ,CAAC,MAAc,EAAE,QAAkB;YACzC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC;QAED,UAAU,CAAC,MAAc;YACvB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QAED,OAAO,CAAC,MAAc;YACpB,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;QAED,GAAG;YACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;gBAChE,MAAM;gBACN,QAAQ;aACT,CAAC,CAAC,CAAC;QACN,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant manager — high-level orchestration.
|
|
3
|
+
*
|
|
4
|
+
* @module repository/tenantManager
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantId } from "../tenancyTypes/tenantIdentity.js";
|
|
7
|
+
import type { Tenant } from "../tenancyTypes/tenantInterface.js";
|
|
8
|
+
import type { TenantResolution } from "../tenancyTypes/resolverTypes.js";
|
|
9
|
+
import type { TenantRepository, TenantCache } from "../tenancyTypes/repositoryTypes.js";
|
|
10
|
+
import type { TenantContextStorage } from "../context/contextStorage.core.js";
|
|
11
|
+
/** Options for the tenant manager. */
|
|
12
|
+
export interface TenantManagerOptions {
|
|
13
|
+
readonly repository: TenantRepository;
|
|
14
|
+
readonly cache?: TenantCache;
|
|
15
|
+
readonly storage: TenantContextStorage;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a tenant manager.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createTenantManager(options: TenantManagerOptions): {
|
|
21
|
+
/**
|
|
22
|
+
* Resolve tenant from a resolution.
|
|
23
|
+
*/
|
|
24
|
+
resolve(resolution: TenantResolution): Promise<Tenant | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Get a tenant by ID.
|
|
27
|
+
*/
|
|
28
|
+
get(id: TenantId): Promise<Tenant | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* Require a tenant by ID — throws if not found.
|
|
31
|
+
*/
|
|
32
|
+
require(id: TenantId): Promise<Tenant>;
|
|
33
|
+
/**
|
|
34
|
+
* Validate that a tenant is in an active state.
|
|
35
|
+
*/
|
|
36
|
+
assertActive(tenant: Tenant): void;
|
|
37
|
+
/**
|
|
38
|
+
* Get the current tenant from context.
|
|
39
|
+
*/
|
|
40
|
+
getCurrent(): Tenant | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Invalidate a cached tenant.
|
|
43
|
+
*/
|
|
44
|
+
invalidate(id: TenantId): Promise<void>;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=tenantManager.core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantManager.core.d.ts","sourceRoot":"","sources":["../../src/repository/tenantManager.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AACjE,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACZ,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAM9E,sCAAsC;AACtC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;CACxC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB;IAmB7D;;OAEG;IACG,OAAO,aAAa,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAIxE;;OAEG;IACG,GAAG,KAAK,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAIpD;;OAEG;IACG,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAM5C;;OAEG;IACH,YAAY,SAAS,MAAM,GAAG,IAAI;IAMlC;;OAEG;IACH,UAAU,IAAI,MAAM,GAAG,SAAS;IAMhC;;OAEG;IACG,UAAU,KAAK,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;EAIhD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant manager — high-level orchestration.
|
|
3
|
+
*
|
|
4
|
+
* @module repository/tenantManager
|
|
5
|
+
*/
|
|
6
|
+
import { TenantNotFoundError, TenantUnavailableError, } from "../tenancyErrors/tenancyError.types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a tenant manager.
|
|
9
|
+
*/
|
|
10
|
+
export function createTenantManager(options) {
|
|
11
|
+
const { repository, cache, storage } = options;
|
|
12
|
+
async function loadTenant(id) {
|
|
13
|
+
// Check cache first
|
|
14
|
+
if (cache) {
|
|
15
|
+
const cached = await cache.get(id);
|
|
16
|
+
if (cached)
|
|
17
|
+
return cached;
|
|
18
|
+
}
|
|
19
|
+
// Load from repository
|
|
20
|
+
const tenant = await repository.findById(id);
|
|
21
|
+
if (tenant && cache) {
|
|
22
|
+
await cache.set(tenant);
|
|
23
|
+
}
|
|
24
|
+
return tenant;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
/**
|
|
28
|
+
* Resolve tenant from a resolution.
|
|
29
|
+
*/
|
|
30
|
+
async resolve(resolution) {
|
|
31
|
+
return loadTenant(resolution.tenantId);
|
|
32
|
+
},
|
|
33
|
+
/**
|
|
34
|
+
* Get a tenant by ID.
|
|
35
|
+
*/
|
|
36
|
+
async get(id) {
|
|
37
|
+
return loadTenant(id);
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* Require a tenant by ID — throws if not found.
|
|
41
|
+
*/
|
|
42
|
+
async require(id) {
|
|
43
|
+
const tenant = await loadTenant(id);
|
|
44
|
+
if (!tenant)
|
|
45
|
+
throw new TenantNotFoundError(id);
|
|
46
|
+
return tenant;
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Validate that a tenant is in an active state.
|
|
50
|
+
*/
|
|
51
|
+
assertActive(tenant) {
|
|
52
|
+
if (tenant.status !== "active") {
|
|
53
|
+
throw new TenantUnavailableError(tenant.id, tenant.status);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Get the current tenant from context.
|
|
58
|
+
*/
|
|
59
|
+
getCurrent() {
|
|
60
|
+
const ctx = storage.get();
|
|
61
|
+
if (ctx?.mode === "tenant")
|
|
62
|
+
return ctx.tenant;
|
|
63
|
+
return undefined;
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* Invalidate a cached tenant.
|
|
67
|
+
*/
|
|
68
|
+
async invalidate(id) {
|
|
69
|
+
if (cache)
|
|
70
|
+
await cache.delete(id);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=tenantManager.core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantManager.core.js","sourceRoot":"","sources":["../../src/repository/tenantManager.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,wCAAwC,CAAC;AAShD;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAE/C,KAAK,UAAU,UAAU,CAAC,EAAY;QACpC,oBAAoB;QACpB,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnC,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;QAC5B,CAAC;QAED,uBAAuB;QACvB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC7C,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;YACpB,MAAM,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO;QACL;;WAEG;QACH,KAAK,CAAC,OAAO,CAAC,UAA4B;YACxC,OAAO,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAED;;WAEG;QACH,KAAK,CAAC,GAAG,CAAC,EAAY;YACpB,OAAO,UAAU,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;QAED;;WAEG;QACH,KAAK,CAAC,OAAO,CAAC,EAAY;YACxB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,mBAAmB,CAAC,EAAE,CAAC,CAAC;YAC/C,OAAO,MAAM,CAAC;QAChB,CAAC;QAED;;WAEG;QACH,YAAY,CAAC,MAAc;YACzB,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,IAAI,sBAAsB,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAED;;WAEG;QACH,UAAU;YACR,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAC1B,IAAI,GAAG,EAAE,IAAI,KAAK,QAAQ;gBAAE,OAAO,GAAG,CAAC,MAAM,CAAC;YAC9C,OAAO,SAAS,CAAC;QACnB,CAAC;QAED;;WAEG;QACH,KAAK,CAAC,UAAU,CAAC,EAAY;YAC3B,IAAI,KAAK;gBAAE,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resolver/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resolver/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolver chain — coordinates multiple resolvers with conflict detection.
|
|
3
|
+
*
|
|
4
|
+
* @module resolver/resolverChain
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantResolver, TenantResolutionResult, ResolverChainOptions } from "../tenancyTypes/resolverTypes.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a resolver chain that tries resolvers in priority order.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createResolverChain<Context = unknown>(resolvers: readonly TenantResolver<Context>[], options?: ResolverChainOptions): {
|
|
11
|
+
/**
|
|
12
|
+
* Resolve tenant from context using the chain.
|
|
13
|
+
*/
|
|
14
|
+
resolve(context: Context): Promise<TenantResolutionResult>;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=resolverChain.core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolverChain.core.d.ts","sourceRoot":"","sources":["../../src/resolver/resolverChain.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,EAEd,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,kCAAkC,CAAC;AAG1C;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAG,OAAO,EACnD,SAAS,EAAE,SAAS,cAAc,CAAC,OAAO,CAAC,EAAE,EAC7C,OAAO,CAAC,EAAE,oBAAoB;IAM5B;;OAEG;IACG,OAAO,UAAU,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;EAoCnE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolver chain — coordinates multiple resolvers with conflict detection.
|
|
3
|
+
*
|
|
4
|
+
* @module resolver/resolverChain
|
|
5
|
+
*/
|
|
6
|
+
import { TenantResolutionConflictError } from "../tenancyErrors/tenancyError.types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a resolver chain that tries resolvers in priority order.
|
|
9
|
+
*/
|
|
10
|
+
export function createResolverChain(resolvers, options) {
|
|
11
|
+
// Sort by priority descending (higher priority first)
|
|
12
|
+
const sorted = [...resolvers].sort((a, b) => b.priority - a.priority);
|
|
13
|
+
return {
|
|
14
|
+
/**
|
|
15
|
+
* Resolve tenant from context using the chain.
|
|
16
|
+
*/
|
|
17
|
+
async resolve(context) {
|
|
18
|
+
const candidates = [];
|
|
19
|
+
for (const resolver of sorted) {
|
|
20
|
+
try {
|
|
21
|
+
const result = await resolver.resolve(context);
|
|
22
|
+
if (result) {
|
|
23
|
+
candidates.push(result);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Skip failed resolvers — continue chain
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (candidates.length === 0) {
|
|
31
|
+
return { resolution: undefined, candidates: [], conflict: false };
|
|
32
|
+
}
|
|
33
|
+
// Check for conflicts
|
|
34
|
+
const uniqueTenantIds = new Set(candidates.map((c) => c.tenantId));
|
|
35
|
+
const hasConflict = uniqueTenantIds.size > 1;
|
|
36
|
+
if (hasConflict && options?.throwOnConflict) {
|
|
37
|
+
throw new TenantResolutionConflictError(candidates.map((c) => `${c.source}:${c.tenantId}`));
|
|
38
|
+
}
|
|
39
|
+
// Use highest priority (first in sorted list)
|
|
40
|
+
return {
|
|
41
|
+
resolution: candidates[0],
|
|
42
|
+
candidates,
|
|
43
|
+
conflict: hasConflict,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=resolverChain.core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolverChain.core.js","sourceRoot":"","sources":["../../src/resolver/resolverChain.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAEvF;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAA6C,EAC7C,OAA8B;IAE9B,sDAAsD;IACtD,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEtE,OAAO;QACL;;WAEG;QACH,KAAK,CAAC,OAAO,CAAC,OAAgB;YAC5B,MAAM,UAAU,GAAuB,EAAE,CAAC;YAE1C,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;gBAC9B,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBAC/C,IAAI,MAAM,EAAE,CAAC;wBACX,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC1B,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,yCAAyC;gBAC3C,CAAC;YACH,CAAC;YAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YACpE,CAAC;YAED,sBAAsB;YACtB,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YACnE,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,GAAG,CAAC,CAAC;YAE7C,IAAI,WAAW,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC5C,MAAM,IAAI,6BAA6B,CACrC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CACnD,CAAC;YACJ,CAAC;YAED,8CAA8C;YAC9C,OAAO;gBACL,UAAU,EAAE,UAAU,CAAC,CAAC,CAAE;gBAC1B,UAAU;gBACV,QAAQ,EAAE,WAAW;aACtB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/headerResolver
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantResolver } from "../../tenancyTypes/resolverTypes.js";
|
|
7
|
+
/** Context type with a getHeader method. */
|
|
8
|
+
interface HeaderContext {
|
|
9
|
+
getHeader(name: string): string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Options for the header resolver. */
|
|
12
|
+
export interface HeaderResolverOptions {
|
|
13
|
+
readonly headerName?: string;
|
|
14
|
+
readonly priority?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a tenant resolver that reads from an HTTP header.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createHeaderResolver(options?: HeaderResolverOptions): TenantResolver<HeaderContext>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=headerResolver.core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headerResolver.core.d.ts","sourceRoot":"","sources":["../../../src/resolver/resolvers/headerResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,qCAAqC,CAAC;AAG7C,4CAA4C;AAC5C,UAAU,aAAa;IACrB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC7C;AAED,uCAAuC;AACvC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,cAAc,CAAC,aAAa,CAAC,CAqB/B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/headerResolver
|
|
5
|
+
*/
|
|
6
|
+
import { createTenantId } from "../../tenancyTypes/tenantIdentity.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a tenant resolver that reads from an HTTP header.
|
|
9
|
+
*/
|
|
10
|
+
export function createHeaderResolver(options) {
|
|
11
|
+
const headerName = options?.headerName ?? "x-tenant-id";
|
|
12
|
+
const priority = options?.priority ?? 80;
|
|
13
|
+
return {
|
|
14
|
+
name: "header",
|
|
15
|
+
priority,
|
|
16
|
+
async resolve(context) {
|
|
17
|
+
const value = context.getHeader(headerName);
|
|
18
|
+
if (!value)
|
|
19
|
+
return undefined;
|
|
20
|
+
return {
|
|
21
|
+
tenantId: createTenantId(value),
|
|
22
|
+
source: "header",
|
|
23
|
+
trust: "verified",
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=headerResolver.core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headerResolver.core.js","sourceRoot":"","sources":["../../../src/resolver/resolvers/headerResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAatE;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAA+B;IAE/B,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,aAAa,CAAC;IACxD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;IAEzC,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,QAAQ;QAER,KAAK,CAAC,OAAO,CACX,OAAsB;YAEtB,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YAC5C,IAAI,CAAC,KAAK;gBAAE,OAAO,SAAS,CAAC;YAE7B,OAAO;gBACL,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC;gBAC/B,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,UAAU;aAClB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in tenant resolvers.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers
|
|
5
|
+
*/
|
|
6
|
+
export { createHeaderResolver, type HeaderResolverOptions, } from "./headerResolver.core.js";
|
|
7
|
+
export { createSubdomainResolver, type SubdomainResolverOptions, } from "./subdomainResolver.core.js";
|
|
8
|
+
export { createPathResolver, type PathResolverOptions, } from "./pathResolver.core.js";
|
|
9
|
+
export { createJwtResolver, type JwtResolverOptions, } from "./jwtResolver.core.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/resolver/resolvers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,oBAAoB,EACpB,KAAK,qBAAqB,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,kBAAkB,EAClB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,GACxB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in tenant resolvers.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers
|
|
5
|
+
*/
|
|
6
|
+
export { createHeaderResolver, } from "./headerResolver.core.js";
|
|
7
|
+
export { createSubdomainResolver, } from "./subdomainResolver.core.js";
|
|
8
|
+
export { createPathResolver, } from "./pathResolver.core.js";
|
|
9
|
+
export { createJwtResolver, } from "./jwtResolver.core.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/resolver/resolvers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,oBAAoB,GAErB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,GAExB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,kBAAkB,GAEnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,GAElB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/jwtResolver
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantResolver } from "../../tenancyTypes/resolverTypes.js";
|
|
7
|
+
/** JWT claims with tenant_id. */
|
|
8
|
+
interface JwtClaims {
|
|
9
|
+
readonly tenant_id?: string;
|
|
10
|
+
readonly [key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
/** Context with a getClaims method. */
|
|
13
|
+
interface JwtContext {
|
|
14
|
+
getClaims(): JwtClaims | undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Options for the JWT resolver. */
|
|
17
|
+
export interface JwtResolverOptions {
|
|
18
|
+
/** Claim key for tenant ID. Defaults to "tenant_id". */
|
|
19
|
+
readonly claimKey?: string;
|
|
20
|
+
readonly priority?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a tenant resolver that reads from JWT claims.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createJwtResolver(options?: JwtResolverOptions): TenantResolver<JwtContext>;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=jwtResolver.core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtResolver.core.d.ts","sourceRoot":"","sources":["../../../src/resolver/resolvers/jwtResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,qCAAqC,CAAC;AAG7C,iCAAiC;AACjC,UAAU,SAAS;IACjB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,uCAAuC;AACvC,UAAU,UAAU;IAClB,SAAS,IAAI,SAAS,GAAG,SAAS,CAAC;CACpC;AAED,oCAAoC;AACpC,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,CAAC,EAAE,kBAAkB,GAC3B,cAAc,CAAC,UAAU,CAAC,CAsB5B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/jwtResolver
|
|
5
|
+
*/
|
|
6
|
+
import { createTenantId } from "../../tenancyTypes/tenantIdentity.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a tenant resolver that reads from JWT claims.
|
|
9
|
+
*/
|
|
10
|
+
export function createJwtResolver(options) {
|
|
11
|
+
const claimKey = options?.claimKey ?? "tenant_id";
|
|
12
|
+
const priority = options?.priority ?? 100;
|
|
13
|
+
return {
|
|
14
|
+
name: "jwt",
|
|
15
|
+
priority,
|
|
16
|
+
async resolve(context) {
|
|
17
|
+
const claims = context.getClaims();
|
|
18
|
+
if (!claims)
|
|
19
|
+
return undefined;
|
|
20
|
+
const tenantId = claims[claimKey];
|
|
21
|
+
if (typeof tenantId !== "string" || !tenantId)
|
|
22
|
+
return undefined;
|
|
23
|
+
return {
|
|
24
|
+
tenantId: createTenantId(tenantId),
|
|
25
|
+
source: "jwt",
|
|
26
|
+
trust: "trusted",
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=jwtResolver.core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtResolver.core.js","sourceRoot":"","sources":["../../../src/resolver/resolvers/jwtResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAoBtE;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAA4B;IAE5B,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,WAAW,CAAC;IAClD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,GAAG,CAAC;IAE1C,OAAO;QACL,IAAI,EAAE,KAAK;QACX,QAAQ;QAER,KAAK,CAAC,OAAO,CAAC,OAAmB;YAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC;YAE9B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAEhE,OAAO;gBACL,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC;gBAClC,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,SAAS;aACjB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/pathResolver
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantResolver } from "../../tenancyTypes/resolverTypes.js";
|
|
7
|
+
/** Context with getPath method. */
|
|
8
|
+
interface PathContext {
|
|
9
|
+
getPath(): string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Options for the path resolver. */
|
|
12
|
+
export interface PathResolverOptions {
|
|
13
|
+
/** Prefix to strip (e.g. "/tenant"). */
|
|
14
|
+
readonly prefix?: string;
|
|
15
|
+
readonly priority?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a tenant resolver that extracts tenant from URL path.
|
|
19
|
+
*
|
|
20
|
+
* Example: "/acme/users" → tenant "acme"
|
|
21
|
+
*/
|
|
22
|
+
export declare function createPathResolver(options?: PathResolverOptions): TenantResolver<PathContext>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=pathResolver.core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathResolver.core.d.ts","sourceRoot":"","sources":["../../../src/resolver/resolvers/pathResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,qCAAqC,CAAC;AAG7C,mCAAmC;AACnC,UAAU,WAAW;IACnB,OAAO,IAAI,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,qCAAqC;AACrC,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,cAAc,CAAC,WAAW,CAAC,CAmC7B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/pathResolver
|
|
5
|
+
*/
|
|
6
|
+
import { createTenantId } from "../../tenancyTypes/tenantIdentity.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a tenant resolver that extracts tenant from URL path.
|
|
9
|
+
*
|
|
10
|
+
* Example: "/acme/users" → tenant "acme"
|
|
11
|
+
*/
|
|
12
|
+
export function createPathResolver(options) {
|
|
13
|
+
const prefix = options?.prefix ?? "";
|
|
14
|
+
const priority = options?.priority ?? 60;
|
|
15
|
+
return {
|
|
16
|
+
name: "path",
|
|
17
|
+
priority,
|
|
18
|
+
async resolve(context) {
|
|
19
|
+
const path = context.getPath();
|
|
20
|
+
if (!path)
|
|
21
|
+
return undefined;
|
|
22
|
+
let segments = path.split("/").filter(Boolean);
|
|
23
|
+
if (prefix) {
|
|
24
|
+
const prefixSegments = prefix.split("/").filter(Boolean);
|
|
25
|
+
if (segments.slice(0, prefixSegments.length).join("/") ===
|
|
26
|
+
prefixSegments.join("/")) {
|
|
27
|
+
segments = segments.slice(prefixSegments.length);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (segments.length === 0)
|
|
31
|
+
return undefined;
|
|
32
|
+
const candidate = segments[0];
|
|
33
|
+
return {
|
|
34
|
+
tenantId: createTenantId(candidate),
|
|
35
|
+
source: "path",
|
|
36
|
+
trust: "untrusted",
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=pathResolver.core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathResolver.core.js","sourceRoot":"","sources":["../../../src/resolver/resolvers/pathResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AActE;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA6B;IAE7B,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;IAEzC,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,QAAQ;QAER,KAAK,CAAC,OAAO,CAAC,OAAoB;YAChC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YAE5B,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAE/C,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACzD,IACE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;oBAClD,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EACxB,CAAC;oBACD,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;YAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAC;YAE5C,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;YAE/B,OAAO;gBACL,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC;gBACnC,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,WAAW;aACnB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subdomain-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/subdomainResolver
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantResolver } from "../../tenancyTypes/resolverTypes.js";
|
|
7
|
+
/** Context type with a getHost method. */
|
|
8
|
+
interface SubdomainContext {
|
|
9
|
+
getHost(): string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Options for the subdomain resolver. */
|
|
12
|
+
export interface SubdomainResolverOptions {
|
|
13
|
+
/** Base domain to strip (e.g. "example.com"). If not set, uses first segment. */
|
|
14
|
+
readonly baseDomain?: string;
|
|
15
|
+
readonly priority?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a tenant resolver that extracts tenant from subdomain.
|
|
19
|
+
*
|
|
20
|
+
* Example: "acme.example.com" → tenant "acme"
|
|
21
|
+
*/
|
|
22
|
+
export declare function createSubdomainResolver(options?: SubdomainResolverOptions): TenantResolver<SubdomainContext>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=subdomainResolver.core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subdomainResolver.core.d.ts","sourceRoot":"","sources":["../../../src/resolver/resolvers/subdomainResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,qCAAqC,CAAC;AAG7C,0CAA0C;AAC1C,UAAU,gBAAgB;IACxB,OAAO,IAAI,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,0CAA0C;AAC1C,MAAM,WAAW,wBAAwB;IACvC,iFAAiF;IACjF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,CAAC,EAAE,wBAAwB,GACjC,cAAc,CAAC,gBAAgB,CAAC,CAwClC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subdomain-based tenant resolver.
|
|
3
|
+
*
|
|
4
|
+
* @module resolvers/subdomainResolver
|
|
5
|
+
*/
|
|
6
|
+
import { createTenantId } from "../../tenancyTypes/tenantIdentity.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a tenant resolver that extracts tenant from subdomain.
|
|
9
|
+
*
|
|
10
|
+
* Example: "acme.example.com" → tenant "acme"
|
|
11
|
+
*/
|
|
12
|
+
export function createSubdomainResolver(options) {
|
|
13
|
+
const priority = options?.priority ?? 70;
|
|
14
|
+
return {
|
|
15
|
+
name: "subdomain",
|
|
16
|
+
priority,
|
|
17
|
+
async resolve(context) {
|
|
18
|
+
const host = context.getHost();
|
|
19
|
+
if (!host)
|
|
20
|
+
return undefined;
|
|
21
|
+
// Strip port
|
|
22
|
+
const hostname = host.split(":")[0];
|
|
23
|
+
if (!hostname)
|
|
24
|
+
return undefined;
|
|
25
|
+
let subdomain;
|
|
26
|
+
if (options?.baseDomain) {
|
|
27
|
+
if (hostname.endsWith(`.${options.baseDomain}`)) {
|
|
28
|
+
subdomain = hostname.slice(0, -(options.baseDomain.length + 1));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Use first segment
|
|
33
|
+
const parts = hostname.split(".");
|
|
34
|
+
if (parts.length > 2) {
|
|
35
|
+
subdomain = parts[0];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!subdomain || subdomain === "www")
|
|
39
|
+
return undefined;
|
|
40
|
+
return {
|
|
41
|
+
tenantId: createTenantId(subdomain),
|
|
42
|
+
source: "subdomain",
|
|
43
|
+
trust: "verified",
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=subdomainResolver.core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subdomainResolver.core.js","sourceRoot":"","sources":["../../../src/resolver/resolvers/subdomainResolver.core.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AActE;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAkC;IAElC,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;IAEzC,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,QAAQ;QAER,KAAK,CAAC,OAAO,CACX,OAAyB;YAEzB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YAE5B,aAAa;YACb,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;YACrC,IAAI,CAAC,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAEhC,IAAI,SAA6B,CAAC;YAElC,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;gBACxB,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;oBAChD,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,oBAAoB;gBACpB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,KAAK;gBAAE,OAAO,SAAS,CAAC;YAExD,OAAO;gBACL,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC;gBACnC,MAAM,EAAE,WAAW;gBACnB,KAAK,EAAE,UAAU;aAClB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|