@usebetterdev/tenant-core 0.1.0 → 0.2.0-beta.9

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 CHANGED
@@ -1,24 +1,23 @@
1
- # @better-tenant/core
1
+ # @usebetterdev/tenant-core
2
2
 
3
- Core library for request-scoped multi-tenancy with Postgres RLS. Provides tenant context (AsyncLocalStorage), resolver strategies, adapter contract, and tenant API. No database driver dependency — use with [@usebetterdev/tenant-drizzle](https://github.com/usebetter-dev/usebetter) or a custom adapter.
3
+ Core library for request-scoped multi-tenancy with Postgres RLS. Provides tenant context (AsyncLocalStorage), resolver strategies, adapter contract, and tenant API. No database driver dependency — use with the Drizzle adapter or a custom adapter.
4
4
 
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- pnpm add @better-tenant/core
8
+ pnpm add @usebetterdev/tenant
9
9
  ```
10
10
 
11
11
  ## Quick start
12
12
 
13
13
  ```ts
14
- import { betterTenant, getContext, getDatabase } from "@better-tenant/core";
15
- import { drizzleAdapter } from "better-tenant/drizzle"; // or your adapter
14
+ import { betterTenant } from "@usebetterdev/tenant";
15
+ import { drizzleAdapter } from "@usebetterdev/tenant/drizzle"; // or your adapter
16
16
 
17
17
  const adapter = drizzleAdapter(db);
18
18
  const tenant = betterTenant({
19
19
  adapter,
20
20
  tenantResolver: { header: "x-tenant-id" },
21
- tenantTables: ["projects", "tasks"],
22
21
  getTenantRepository: (database) => ({ create, update, list, delete }), // adapter provides this
23
22
  });
24
23
 
@@ -38,9 +37,9 @@ const database = tenant.getDatabase(); // tenant-scoped DB handle (use only
38
37
  | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
39
38
  | `betterTenant(config)` | Create instance with adapter, resolver, optional `getTenantRepository`. |
40
39
  | `getContext()` | Current `TenantContext \| undefined` (tenantId, tenant?, database?). |
41
- | `getDatabase()` | Tenant-scoped database handle, or `undefined` outside request scope. Use only this for tenant-scoped tables. |
40
+ | `tenant.getDatabase()` | Tenant-scoped database handle, or `undefined` outside request scope. Use only this for tenant-scoped tables. |
42
41
  | `runWithTenant(tenantId, fn)` | Run `fn` with context only (no DB). For tests or when adapter not used. |
43
- | `runWithTenantAndDatabase(tenantId, adapter, fn)` | Set context and run `fn` with adapters tenant-scoped DB. Call from middleware. |
42
+ | `runWithTenantAndDatabase(tenantId, adapter, fn)` | Set context and run `fn` with adapter's tenant-scoped DB. Call from middleware. |
44
43
  | `resolveTenant(request, config)` / `resolveTenantAsync` | Resolve tenant id from request (header, path, subdomain, jwt, custom). |
45
44
  | `runAs(tenantId, adapter, fn)` | Same as request flow; use for cron or per-tenant jobs. |
46
45
  | `runAsSystem(fn)` | Run with RLS bypass (adapter must implement `runAsSystem`). |
package/dist/adapter.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TenantAdapter, TenantScopedDatabase, RunWithTenantAndDatabaseOptions } from "./types.js";
1
+ import type { TenantAdapter, RunWithTenantAndDatabaseOptions } from "./types.js";
2
2
  /**
3
3
  * Returns the tenant-scoped database handle when inside a runWithTenantAndDatabase (or runAs) scope.
4
4
  *
@@ -6,7 +6,7 @@ import type { TenantAdapter, TenantScopedDatabase, RunWithTenantAndDatabaseOptio
6
6
  * Config requires an adapter when tenant-scoped DB is used; getDatabase() is then available inside
7
7
  * request handlers that ran via runWithTenantAndDatabase(tenantId, adapter, next).
8
8
  */
9
- export declare function getDatabase(): TenantScopedDatabase | undefined;
9
+ export declare function getDatabase(): unknown;
10
10
  /**
11
11
  * Sets AsyncLocalStorage context and runs fn with the adapter's tenant-scoped DB.
12
12
  *
@@ -20,5 +20,5 @@ export declare function getDatabase(): TenantScopedDatabase | undefined;
20
20
  * When options.loadTenant is true and options.getTenantRepository and adapter.runAsSystem are set,
21
21
  * loads the full Tenant row into context so getContext().tenant is available (or undefined if not found).
22
22
  */
23
- export declare function runWithTenantAndDatabase<T>(tenantId: string, adapter: TenantAdapter, fn: (database: TenantScopedDatabase) => Promise<T>, options?: RunWithTenantAndDatabaseOptions): Promise<T>;
23
+ export declare function runWithTenantAndDatabase<TDb, SDb, T>(tenantId: string, adapter: TenantAdapter<TDb, SDb>, fn: (database: TDb) => Promise<T>, options?: RunWithTenantAndDatabaseOptions<SDb>): Promise<T>;
24
24
  //# sourceMappingURL=adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAEb,oBAAoB,EACpB,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAGpB;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,oBAAoB,GAAG,SAAS,CAG9D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,EACtB,EAAE,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,OAAO,CAAC,CAAC,CAAC,EAClD,OAAO,CAAC,EAAE,+BAA+B,GACxC,OAAO,CAAC,CAAC,CAAC,CAgBZ"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAEb,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAGpB;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAGrC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EACxD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EAChC,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,EACjC,OAAO,CAAC,EAAE,+BAA+B,CAAC,GAAG,CAAC,GAC7C,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
package/dist/api.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TenantAdapter, Tenant, SystemDatabase, TenantScopedDatabase, TenantRepository } from "./types.js";
1
+ import type { TenantAdapter, Tenant, TenantRepository } from "./types.js";
2
2
  export interface CreateTenantData {
3
3
  name: string;
4
4
  slug: string;
@@ -14,7 +14,7 @@ export interface ListTenantsOptions {
14
14
  /**
15
15
  * Tenant CRUD API. All methods run via adapter.runAsSystem and getTenantRepository.
16
16
  */
17
- export declare function createTenantApi(adapter: TenantAdapter, getTenantRepository: (database: SystemDatabase) => TenantRepository): {
17
+ export declare function createTenantApi<TDb, SDb>(adapter: TenantAdapter<TDb, SDb>, getTenantRepository: (database: SDb) => TenantRepository): {
18
18
  createTenant(data: CreateTenantData): Promise<Tenant>;
19
19
  updateTenant(tenantId: string, data: UpdateTenantData): Promise<Tenant>;
20
20
  listTenants(options?: ListTenantsOptions): Promise<Tenant[]>;
@@ -24,10 +24,10 @@ export declare function createTenantApi(adapter: TenantAdapter, getTenantReposit
24
24
  * runAs(tenantId, fn): same as request flow — set context + run inside adapter.runWithTenant
25
25
  * so code can use getDatabase() and run tenant-scoped queries. Use for cron, per-tenant migrations.
26
26
  */
27
- export declare function runAs<T>(tenantId: string, adapter: TenantAdapter, fn: (database: TenantScopedDatabase) => Promise<T>): Promise<T>;
27
+ export declare function runAs<TDb, T>(tenantId: string, adapter: TenantAdapter<TDb>, fn: (database: TDb) => Promise<T>): Promise<T>;
28
28
  /**
29
29
  * runAsSystem(fn): run fn with a DB handle that has RLS bypass.
30
30
  * Optionally set context so getContext() reflects system mode.
31
31
  */
32
- export declare function runAsSystem<T>(adapter: TenantAdapter, fn: (database: SystemDatabase) => Promise<T>): Promise<T>;
32
+ export declare function runAsSystem<SDb, T>(adapter: TenantAdapter<unknown, SDb>, fn: (database: SDb) => Promise<T>): Promise<T>;
33
33
  //# sourceMappingURL=api.d.ts.map
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,MAAM,EACN,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAOpB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwBD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,aAAa,EACtB,mBAAmB,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,gBAAgB;uBAMxC,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;2BAgB/C,MAAM,QACV,gBAAgB,GACrB,OAAO,CAAC,MAAM,CAAC;0BAYS,kBAAkB,GAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;2BAWzC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;EAStD;AAED;;;GAGG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,EACtB,EAAE,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,OAAO,CAAC,CAAC,CAAC,GACjD,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,OAAO,EAAE,aAAa,EACtB,EAAE,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3C,OAAO,CAAC,CAAC,CAAC,CAKZ"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAO1E,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwBD;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EACtC,OAAO,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EAChC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,gBAAgB;uBAM7B,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;2BAgB/C,MAAM,QACV,gBAAgB,GACrB,OAAO,CAAC,MAAM,CAAC;0BAYS,kBAAkB,GAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;2BAWzC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;EAStD;AAED;;;GAGG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,CAAC,EAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,EAC3B,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAChC,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,CAAC,EACtC,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,EACpC,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAChC,OAAO,CAAC,CAAC,CAAC,CAGZ"}
@@ -1,8 +1,6 @@
1
- import type { BetterTenantConfig, Tenant, ResolvableRequest, SystemDatabase } from "./types.js";
2
- import { getContext, runWithTenant } from "./context.js";
3
- import { getDatabase, runWithTenantAndDatabase } from "./adapter.js";
1
+ import type { BetterTenantConfig, Tenant, ResolvableRequest, TenantContext, TenantAdapter, RunWithTenantAndDatabaseOptions } from "./types.js";
2
+ import { runWithTenant } from "./context.js";
4
3
  import { type HandleRequestOptions } from "./handle-request.js";
5
- import { runAs } from "./api.js";
6
4
  export interface TenantApi {
7
5
  createTenant(data: {
8
6
  name: string;
@@ -18,13 +16,13 @@ export interface TenantApi {
18
16
  }): Promise<Tenant[]>;
19
17
  deleteTenant(tenantId: string): Promise<void>;
20
18
  }
21
- export interface BetterTenantInstance {
22
- getContext: typeof getContext;
23
- getDatabase: typeof getDatabase;
19
+ export interface BetterTenantInstance<TDb = unknown, SDb = unknown> {
20
+ getContext: () => TenantContext | undefined;
21
+ getDatabase: () => TDb | undefined;
24
22
  runWithTenant: typeof runWithTenant;
25
- runWithTenantAndDatabase: typeof runWithTenantAndDatabase;
26
- runAs: typeof runAs;
27
- runAsSystem: <T>(fn: (database: SystemDatabase) => Promise<T>) => Promise<T>;
23
+ runWithTenantAndDatabase: <T>(tenantId: string, adapter: TenantAdapter<TDb, SDb>, fn: (database: TDb) => Promise<T>, options?: RunWithTenantAndDatabaseOptions<SDb>) => Promise<T>;
24
+ runAs: <T>(tenantId: string, adapter: TenantAdapter<TDb>, fn: (database: TDb) => Promise<T>) => Promise<T>;
25
+ runAsSystem: <T>(fn: (database: SDb) => Promise<T>) => Promise<T>;
28
26
  resolveTenant: (request: ResolvableRequest) => string | undefined;
29
27
  resolveTenantAsync: (request: ResolvableRequest) => Promise<string | undefined>;
30
28
  handleRequest: <Req extends ResolvableRequest, Result>(request: Req, next: () => Promise<Result>, options?: Omit<HandleRequestOptions<Req, Result>, "resolveTenant" | "adapter">) => Promise<Result>;
@@ -36,5 +34,5 @@ export interface BetterTenantInstance {
36
34
  * Creates the Better Tenant instance. Config must include adapter and tenantResolver.
37
35
  * When getTenantRepository is provided, tenant.api is available for CRUD on the tenants table.
38
36
  */
39
- export declare function betterTenant(config: BetterTenantConfig): BetterTenantInstance;
37
+ export declare function betterTenant<TDb, SDb>(config: BetterTenantConfig<TDb, SDb>): BetterTenantInstance<TDb, SDb>;
40
38
  //# sourceMappingURL=better-tenant.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"better-tenant.d.ts","sourceRoot":"","sources":["../src/better-tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,MAAM,EACN,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,EAEN,MAAM,UAAU,CAAC;AAGlB,MAAM,WAAW,SAAS;IACxB,YAAY,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,YAAY,CACV,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GACrC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,WAAW,EAAE,OAAO,WAAW,CAAC;IAChC,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;IAC1D,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7E,aAAa,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,MAAM,GAAG,SAAS,CAAC;IAClE,kBAAkB,EAAE,CAClB,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,aAAa,EAAE,CAAC,GAAG,SAAS,iBAAiB,EAAE,MAAM,EACnD,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAC3B,OAAO,CAAC,EAAE,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,KAC3E,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE;QAAE,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,oBAAoB,CAmC7E"}
1
+ {"version":3,"file":"better-tenant.d.ts","sourceRoot":"","sources":["../src/better-tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,MAAM,EACN,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAc,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,WAAW,SAAS;IACxB,YAAY,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,YAAY,CACV,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GACrC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,oBAAoB,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO;IAChE,UAAU,EAAE,MAAM,aAAa,GAAG,SAAS,CAAC;IAC5C,WAAW,EAAE,MAAM,GAAG,GAAG,SAAS,CAAC;IACnC,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,wBAAwB,EAAE,CAAC,CAAC,EAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EAChC,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,EACjC,OAAO,CAAC,EAAE,+BAA+B,CAAC,GAAG,CAAC,KAC3C,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,EACP,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,EAC3B,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,KAC9B,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAClE,aAAa,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,MAAM,GAAG,SAAS,CAAC;IAClE,kBAAkB,EAAE,CAClB,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,aAAa,EAAE,CAAC,GAAG,SAAS,iBAAiB,EAAE,MAAM,EACnD,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAC3B,OAAO,CAAC,EAAE,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,KAC3E,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE;QAAE,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,CAmC3G"}
package/dist/index.cjs CHANGED
@@ -25,7 +25,6 @@ __export(index_exports, {
25
25
  betterTenant: () => betterTenant,
26
26
  createTenantApi: () => createTenantApi,
27
27
  getContext: () => getContext,
28
- getDatabase: () => getDatabase,
29
28
  handleRequest: () => handleRequest,
30
29
  resolveTenant: () => resolveTenant,
31
30
  resolveTenantAsync: () => resolveTenantAsync,
@@ -55,7 +54,7 @@ function getTelemetryTenantConfig(config) {
55
54
  jwt: !!r.jwt,
56
55
  custom: !!r.custom
57
56
  },
58
- tenantTablesCount: config.tenantTables?.length ?? 0,
57
+ tenantTablesCount: 0,
59
58
  hasGetTenantRepository: !!config.getTenantRepository,
60
59
  loadTenant: config.loadTenant,
61
60
  basePathSet: !!config.basePath,
@@ -72,7 +71,9 @@ function getTelemetryCliConfig(config) {
72
71
  function getAnonymousId(cwd) {
73
72
  try {
74
73
  const pkgPath = (0, import_node_path.join)(cwd, "package.json");
75
- if (!(0, import_node_fs.existsSync)(pkgPath)) return void 0;
74
+ if (!(0, import_node_fs.existsSync)(pkgPath)) {
75
+ return void 0;
76
+ }
76
77
  const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
77
78
  const name = typeof pkg?.name === "string" ? pkg.name : "";
78
79
  const basePath = typeof pkg?.betterTenant?.basePath === "string" ? pkg.betterTenant.basePath : "";
@@ -101,22 +102,34 @@ function detectRuntime() {
101
102
  }
102
103
  function detectEnvironment() {
103
104
  const env = process.env.NODE_ENV || "development";
104
- if (env === "test") return "test";
105
+ if (env === "test") {
106
+ return "test";
107
+ }
105
108
  if (process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true" || process.env.GITLAB_CI === "true" || process.env.CIRCLECI === "true") {
106
109
  return "ci";
107
110
  }
108
- if (env === "production") return "production";
111
+ if (env === "production") {
112
+ return "production";
113
+ }
109
114
  return "development";
110
115
  }
111
116
  function detectFramework(cwd) {
112
117
  try {
113
118
  const pkgPath = (0, import_node_path.join)(cwd, "package.json");
114
- if (!(0, import_node_fs.existsSync)(pkgPath)) return void 0;
119
+ if (!(0, import_node_fs.existsSync)(pkgPath)) {
120
+ return void 0;
121
+ }
115
122
  const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
116
123
  const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
117
- if (deps["next"]) return { name: "next", version: deps["next"] };
118
- if (deps["hono"]) return { name: "hono", version: deps["hono"] };
119
- if (deps["express"]) return { name: "express", version: deps["express"] };
124
+ if (deps["next"]) {
125
+ return { name: "next", version: deps["next"] };
126
+ }
127
+ if (deps["hono"]) {
128
+ return { name: "hono", version: deps["hono"] };
129
+ }
130
+ if (deps["express"]) {
131
+ return { name: "express", version: deps["express"] };
132
+ }
120
133
  return void 0;
121
134
  } catch {
122
135
  return void 0;
@@ -125,12 +138,17 @@ function detectFramework(cwd) {
125
138
  function detectDatabase(cwd) {
126
139
  try {
127
140
  const pkgPath = (0, import_node_path.join)(cwd, "package.json");
128
- if (!(0, import_node_fs.existsSync)(pkgPath)) return void 0;
141
+ if (!(0, import_node_fs.existsSync)(pkgPath)) {
142
+ return void 0;
143
+ }
129
144
  const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
130
145
  const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
131
- if (deps["drizzle-orm"])
146
+ if (deps["drizzle-orm"]) {
132
147
  return { name: "drizzle", version: deps["drizzle-orm"] };
133
- if (deps["prisma"]) return { name: "prisma", version: deps["prisma"] };
148
+ }
149
+ if (deps["prisma"]) {
150
+ return { name: "prisma", version: deps["prisma"] };
151
+ }
134
152
  return void 0;
135
153
  } catch {
136
154
  return void 0;
@@ -151,31 +169,46 @@ function detectSystem() {
151
169
  }
152
170
  function detectPackageManager() {
153
171
  const ua = process.env.npm_config_user_agent;
154
- if (!ua || typeof ua !== "string") return void 0;
172
+ if (!ua || typeof ua !== "string") {
173
+ return void 0;
174
+ }
155
175
  const match = ua.match(/^(.+?)\/(\d+\.\d+\.\d+.*?)(?:\s|$)/);
156
176
  if (match) {
157
177
  const name = (match[1] ?? "unknown").toLowerCase();
158
178
  const version = match[2];
159
179
  return version ? { name, version } : { name };
160
180
  }
161
- if (ua.includes("pnpm")) return { name: "pnpm" };
162
- if (ua.includes("yarn")) return { name: "yarn" };
181
+ if (ua.includes("pnpm")) {
182
+ return { name: "pnpm" };
183
+ }
184
+ if (ua.includes("yarn")) {
185
+ return { name: "yarn" };
186
+ }
163
187
  return { name: "npm" };
164
188
  }
165
189
  function isTelemetryEnabled(options) {
166
- if (process.env.NODE_ENV === "test") return false;
190
+ if (process.env.NODE_ENV === "test") {
191
+ return false;
192
+ }
167
193
  const env = process.env.BETTER_TENANT_TELEMETRY;
168
- if (env === "0" || env?.toLowerCase() === "false") return false;
169
- if (env === "1" || env?.toLowerCase() === "true") return true;
194
+ if (env === "0" || env?.toLowerCase() === "false") {
195
+ return false;
196
+ }
197
+ if (env === "1" || env?.toLowerCase() === "true") {
198
+ return true;
199
+ }
170
200
  return options?.enabled !== false;
171
201
  }
172
202
  function isDebugMode(options) {
173
- if (process.env.BETTER_TENANT_TELEMETRY_DEBUG === "1") return true;
203
+ if (process.env.BETTER_TENANT_TELEMETRY_DEBUG === "1") {
204
+ return true;
205
+ }
174
206
  return options?.debug === true;
175
207
  }
176
208
  function sendTelemetry(type, payload, options) {
177
- if (!isTelemetryEnabled(options))
209
+ if (!isTelemetryEnabled(options)) {
178
210
  return options?.wait ? Promise.resolve() : void 0;
211
+ }
179
212
  const fullPayload = {
180
213
  library: LIBRARY_ID,
181
214
  type,
@@ -273,9 +306,10 @@ function getDatabase() {
273
306
  async function runWithTenantAndDatabase(tenantId, adapter, fn, options) {
274
307
  const result = await adapter.runWithTenant(tenantId, async (database) => {
275
308
  let context = { tenantId, database };
276
- if (options?.loadTenant && options.getTenantRepository && adapter.runAsSystem) {
309
+ const getTenantRepository = options?.getTenantRepository;
310
+ if (options?.loadTenant && getTenantRepository && adapter.runAsSystem) {
277
311
  const tenant = await adapter.runAsSystem(
278
- (systemDb) => options.getTenantRepository(systemDb).getById(tenantId)
312
+ (systemDb) => getTenantRepository(systemDb).getById(tenantId)
279
313
  );
280
314
  context = tenant != null ? { ...context, tenant } : context;
281
315
  }
@@ -402,10 +436,7 @@ async function runAs(tenantId, adapter, fn) {
402
436
  }
403
437
  async function runAsSystem(adapter, fn) {
404
438
  const run = requireRunAsSystem(adapter);
405
- return runWithContext(
406
- { tenantId: "", isSystem: true },
407
- () => run(fn)
408
- );
439
+ return runWithContext({ tenantId: "", isSystem: true }, () => run(fn));
409
440
  }
410
441
 
411
442
  // src/resolver.ts
@@ -416,17 +447,23 @@ function getHeader(headers, name) {
416
447
  return value2?.trim() || void 0;
417
448
  }
418
449
  const raw = headers[key] ?? headers[name];
419
- if (raw === void 0) return void 0;
450
+ if (raw === void 0) {
451
+ return void 0;
452
+ }
420
453
  const value = Array.isArray(raw) ? raw[0] : raw;
421
454
  return (typeof value === "string" ? value : "").trim() || void 0;
422
455
  }
423
456
  function resolveFromHeader(request, headerName) {
424
- if (!headerName) return void 0;
457
+ if (!headerName) {
458
+ return void 0;
459
+ }
425
460
  return getHeader(request.headers, headerName);
426
461
  }
427
462
  function resolveFromPath(request, pathConfig) {
428
463
  const pathOrUrl = request.path ?? request.url;
429
- if (!pathOrUrl) return void 0;
464
+ if (!pathOrUrl) {
465
+ return void 0;
466
+ }
430
467
  let path;
431
468
  try {
432
469
  path = pathOrUrl.startsWith("http") ? new URL(pathOrUrl).pathname : pathOrUrl;
@@ -446,11 +483,17 @@ function parseTenantSegmentIndex(pattern) {
446
483
  }
447
484
  function resolveFromSubdomain(request, config) {
448
485
  const host = request.host ?? (request.url ? new URL(request.url).host : "");
449
- if (!host) return void 0;
486
+ if (!host) {
487
+ return void 0;
488
+ }
450
489
  const hostname = host.split(":")[0];
451
- if (!hostname) return void 0;
490
+ if (!hostname) {
491
+ return void 0;
492
+ }
452
493
  const parts = hostname.split(".");
453
- if (parts.length <= 2) return void 0;
494
+ if (parts.length <= 2) {
495
+ return void 0;
496
+ }
454
497
  const index = config === true ? 0 : typeof config === "object" && config.segmentIndex !== void 0 ? config.segmentIndex : 0;
455
498
  const value = parts[index];
456
499
  return typeof value === "string" && value.length > 0 ? value : void 0;
@@ -458,86 +501,146 @@ function resolveFromSubdomain(request, config) {
458
501
  function decodeJwtPayload(token) {
459
502
  try {
460
503
  const parts = token.split(".");
461
- if (parts.length < 2) return null;
504
+ if (parts.length < 2) {
505
+ return null;
506
+ }
462
507
  const payload = parts[1];
463
- if (!payload) return null;
508
+ if (!payload) {
509
+ return null;
510
+ }
464
511
  const decoded = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
465
- return JSON.parse(decoded);
512
+ const parsed = JSON.parse(decoded);
513
+ if (typeof parsed !== "object" || parsed === null) {
514
+ return null;
515
+ }
516
+ return parsed;
466
517
  } catch {
467
518
  return null;
468
519
  }
469
520
  }
470
521
  function resolveFromJwt(request, config) {
471
522
  const getToken = request.getToken;
472
- if (!getToken) return void 0;
523
+ if (!getToken) {
524
+ return void 0;
525
+ }
473
526
  const token = typeof getToken === "function" ? getToken() : getToken;
474
527
  const value = token instanceof Promise ? void 0 : token ?? void 0;
475
528
  const resolved = value ?? void 0;
476
- if (!resolved) return void 0;
529
+ if (!resolved) {
530
+ return void 0;
531
+ }
477
532
  const claim = typeof config === "string" ? config : config.claim;
478
- if (!claim) return void 0;
479
- const payload = decodeJwtPayload(resolved);
480
- if (!payload) return void 0;
533
+ if (!claim) {
534
+ return void 0;
535
+ }
536
+ const verifyToken = typeof config === "object" ? config.verifyToken : void 0;
537
+ let payload;
538
+ if (verifyToken) {
539
+ const result = verifyToken(resolved);
540
+ if (result instanceof Promise) {
541
+ return void 0;
542
+ }
543
+ payload = result;
544
+ } else {
545
+ payload = decodeJwtPayload(resolved);
546
+ }
547
+ if (!payload) {
548
+ return void 0;
549
+ }
481
550
  const claimValue = payload[claim];
482
551
  return typeof claimValue === "string" && claimValue.length > 0 ? claimValue : void 0;
483
552
  }
484
553
  async function resolveFromJwtAsync(request, config) {
485
554
  const getToken = request.getToken;
486
- if (!getToken) return void 0;
555
+ if (!getToken) {
556
+ return void 0;
557
+ }
487
558
  const token = typeof getToken === "function" ? getToken() : getToken;
488
559
  const value = token instanceof Promise ? await token : token;
489
560
  const resolved = value ?? void 0;
490
- if (!resolved) return void 0;
561
+ if (!resolved) {
562
+ return void 0;
563
+ }
491
564
  const claim = typeof config === "string" ? config : config.claim;
492
- if (!claim) return void 0;
493
- const payload = decodeJwtPayload(resolved);
494
- if (!payload) return void 0;
565
+ if (!claim) {
566
+ return void 0;
567
+ }
568
+ const verifyToken = typeof config === "object" ? config.verifyToken : void 0;
569
+ let payload;
570
+ if (verifyToken) {
571
+ payload = await verifyToken(resolved);
572
+ } else {
573
+ payload = decodeJwtPayload(resolved);
574
+ }
575
+ if (!payload) {
576
+ return void 0;
577
+ }
495
578
  const claimValue = payload[claim];
496
579
  return typeof claimValue === "string" && claimValue.length > 0 ? claimValue : void 0;
497
580
  }
498
581
  function resolveTenant(request, config) {
499
582
  if (config.header !== void 0) {
500
583
  const v = resolveFromHeader(request, config.header);
501
- if (v !== void 0) return v;
584
+ if (v !== void 0) {
585
+ return v;
586
+ }
502
587
  }
503
588
  if (config.path !== void 0) {
504
589
  const v = resolveFromPath(request, config.path);
505
- if (v !== void 0) return v;
590
+ if (v !== void 0) {
591
+ return v;
592
+ }
506
593
  }
507
594
  if (config.subdomain !== void 0 && config.subdomain !== false) {
508
595
  const v = resolveFromSubdomain(request, config.subdomain);
509
- if (v !== void 0) return v;
596
+ if (v !== void 0) {
597
+ return v;
598
+ }
510
599
  }
511
600
  if (config.jwt !== void 0) {
512
601
  const v = resolveFromJwt(request, config.jwt);
513
- if (v !== void 0) return v;
602
+ if (v !== void 0) {
603
+ return v;
604
+ }
514
605
  }
515
606
  if (config.custom !== void 0) {
516
607
  const v = config.custom(request);
517
- if (typeof v === "string" && v.length > 0) return v;
608
+ if (typeof v === "string" && v.length > 0) {
609
+ return v;
610
+ }
518
611
  }
519
612
  return void 0;
520
613
  }
521
614
  async function resolveTenantAsync(request, config) {
522
615
  if (config.header !== void 0) {
523
616
  const v = resolveFromHeader(request, config.header);
524
- if (v !== void 0) return v;
617
+ if (v !== void 0) {
618
+ return v;
619
+ }
525
620
  }
526
621
  if (config.path !== void 0) {
527
622
  const v = resolveFromPath(request, config.path);
528
- if (v !== void 0) return v;
623
+ if (v !== void 0) {
624
+ return v;
625
+ }
529
626
  }
530
627
  if (config.subdomain !== void 0 && config.subdomain !== false) {
531
628
  const v = resolveFromSubdomain(request, config.subdomain);
532
- if (v !== void 0) return v;
629
+ if (v !== void 0) {
630
+ return v;
631
+ }
533
632
  }
534
633
  if (config.jwt !== void 0) {
535
634
  const v = await resolveFromJwtAsync(request, config.jwt);
536
- if (v !== void 0) return v;
635
+ if (v !== void 0) {
636
+ return v;
637
+ }
537
638
  }
538
639
  if (config.custom !== void 0) {
539
640
  const v = await Promise.resolve(config.custom(request));
540
- if (typeof v === "string" && v.length > 0) return v;
641
+ if (typeof v === "string" && v.length > 0) {
642
+ return v;
643
+ }
541
644
  }
542
645
  return void 0;
543
646
  }
@@ -551,7 +654,7 @@ function betterTenant(config) {
551
654
  const runWithTenantAndDatabaseOptions = shouldLoadTenant ? { loadTenant: true, getTenantRepository } : void 0;
552
655
  return {
553
656
  getContext,
554
- getDatabase,
657
+ getDatabase: () => getDatabase(),
555
658
  runWithTenant,
556
659
  runWithTenantAndDatabase: (tenantId, _adapter, fn) => runWithTenantAndDatabase(tenantId, adapter, fn, runWithTenantAndDatabaseOptions),
557
660
  runAs: (tenantId, _adapter, fn) => runAs(tenantId, adapter, fn),
@@ -585,12 +688,16 @@ function isFetchRequest(input) {
585
688
  return typeof Request !== "undefined" && input instanceof Request;
586
689
  }
587
690
  function normalizeHost(raw) {
588
- if (!raw) return void 0;
691
+ if (!raw) {
692
+ return void 0;
693
+ }
589
694
  const value = raw.split(":")[0]?.trim();
590
695
  return value || void 0;
591
696
  }
592
697
  function normalizeHeaders(headers) {
593
- if (!headers) return {};
698
+ if (!headers) {
699
+ return {};
700
+ }
594
701
  const normalized = {};
595
702
  for (const [key, value] of Object.entries(headers)) {
596
703
  const normalizedKey = key.toLowerCase();
@@ -607,7 +714,9 @@ function normalizeHeaders(headers) {
607
714
  return normalized;
608
715
  }
609
716
  function pathWithoutQuery(value) {
610
- if (!value) return void 0;
717
+ if (!value) {
718
+ return void 0;
719
+ }
611
720
  const [pathname] = value.split("?");
612
721
  return pathname || void 0;
613
722
  }
@@ -641,7 +750,9 @@ function toResolvableRequest(request) {
641
750
  const hostFromHeaders = headers.host;
642
751
  const hostValue = Array.isArray(hostFromHeaders) ? hostFromHeaders[0] : hostFromHeaders;
643
752
  const host = normalizeHost(request.hostname ?? request.host ?? hostValue);
644
- const path = pathWithoutQuery(request.path ?? request.originalUrl ?? request.url);
753
+ const path = pathWithoutQuery(
754
+ request.path ?? request.originalUrl ?? request.url
755
+ );
645
756
  const resolved = {
646
757
  headers
647
758
  };
@@ -663,7 +774,6 @@ function toResolvableRequest(request) {
663
774
  betterTenant,
664
775
  createTenantApi,
665
776
  getContext,
666
- getDatabase,
667
777
  handleRequest,
668
778
  resolveTenant,
669
779
  resolveTenantAsync,