@object-ui/tenant 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 ObjectQL
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import type { TenantContext } from '@object-ui/types';
9
+ export interface TenantContextValue extends TenantContext {
10
+ /** Switch to a different tenant */
11
+ switchTenant: (tenantId: string) => Promise<void>;
12
+ /** Whether tenant is loading */
13
+ isLoading: boolean;
14
+ /** Error if tenant resolution failed */
15
+ error: Error | null;
16
+ }
17
+ export declare const TenantCtx: import("react").Context<TenantContextValue | null>;
18
+ //# sourceMappingURL=TenantContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TenantContext.d.ts","sourceRoot":"","sources":["../src/TenantContext.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,mCAAmC;IACnC,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,gCAAgC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,SAAS,oDAAiD,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import { createContext } from 'react';
9
+ export const TenantCtx = createContext(null);
10
+ TenantCtx.displayName = 'TenantContext';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import React from 'react';
9
+ export interface TenantGuardProps {
10
+ /** Required feature flag */
11
+ feature?: string;
12
+ /** Required tenant plan(s) */
13
+ plan?: string | string[];
14
+ /** Required tenant status */
15
+ status?: string;
16
+ /** Fallback content when guard fails */
17
+ fallback?: React.ReactNode;
18
+ /** Children to render when guard passes */
19
+ children: React.ReactNode;
20
+ }
21
+ /**
22
+ * Guard component that conditionally renders children based on tenant configuration.
23
+ * Useful for feature gating and plan-based access control.
24
+ */
25
+ export declare function TenantGuard({ feature, plan, status, fallback, children, }: TenantGuardProps): import("react/jsx-runtime").JSX.Element;
26
+ //# sourceMappingURL=TenantGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TenantGuard.d.ts","sourceRoot":"","sources":["../src/TenantGuard.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,2CAA2C;IAC3C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,IAAI,EACJ,MAAM,EACN,QAAe,EACf,QAAQ,GACT,EAAE,gBAAgB,2CA0BlB"}
@@ -0,0 +1,28 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useTenant } from './useTenant';
3
+ /**
4
+ * Guard component that conditionally renders children based on tenant configuration.
5
+ * Useful for feature gating and plan-based access control.
6
+ */
7
+ export function TenantGuard({ feature, plan, status, fallback = null, children, }) {
8
+ const tenantCtx = useTenant();
9
+ if (!tenantCtx) {
10
+ return _jsx(_Fragment, { children: fallback });
11
+ }
12
+ // Check feature flag
13
+ if (feature && !tenantCtx.features[feature]) {
14
+ return _jsx(_Fragment, { children: fallback });
15
+ }
16
+ // Check plan
17
+ if (plan) {
18
+ const allowedPlans = Array.isArray(plan) ? plan : [plan];
19
+ if (tenantCtx.tenant.plan && !allowedPlans.includes(tenantCtx.tenant.plan)) {
20
+ return _jsx(_Fragment, { children: fallback });
21
+ }
22
+ }
23
+ // Check status
24
+ if (status && tenantCtx.tenant.status !== status) {
25
+ return _jsx(_Fragment, { children: fallback });
26
+ }
27
+ return _jsx(_Fragment, { children: children });
28
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import React from 'react';
9
+ import type { TenantConfig, TenantBranding, TenantProviderConfig } from '@object-ui/types';
10
+ export interface TenantProviderProps {
11
+ /** Tenant configuration or function to resolve tenant */
12
+ tenant?: TenantConfig;
13
+ /** Tenant provider configuration */
14
+ config?: TenantProviderConfig;
15
+ /** Callback to fetch tenant by ID */
16
+ fetchTenant?: (tenantId: string) => Promise<TenantConfig>;
17
+ /** Default branding to merge with tenant branding */
18
+ defaultBranding?: Partial<TenantBranding>;
19
+ /** Children */
20
+ children: React.ReactNode;
21
+ }
22
+ export declare function TenantProvider({ tenant: initialTenant, config, fetchTenant, defaultBranding, children, }: TenantProviderProps): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=TenantProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TenantProvider.d.ts","sourceRoot":"","sources":["../src/TenantProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAG3F,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,oCAAoC;IACpC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,qCAAqC;IACrC,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1D,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1C,eAAe;IACf,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAQD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EAAE,aAAa,EACrB,MAAM,EACN,WAAW,EACX,eAAe,EACf,QAAQ,GACT,EAAE,mBAAmB,2CA4ErB"}
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * ObjectUI
4
+ * Copyright (c) 2024-present ObjectStack Inc.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ import { useState, useEffect, useCallback, useMemo } from 'react';
10
+ import { TenantCtx } from './TenantContext';
11
+ const DEFAULT_BRANDING = {
12
+ companyName: 'ObjectUI',
13
+ primaryColor: '#3b82f6',
14
+ secondaryColor: '#64748b',
15
+ };
16
+ export function TenantProvider({ tenant: initialTenant, config, fetchTenant, defaultBranding, children, }) {
17
+ const [tenant, setTenant] = useState(initialTenant ?? null);
18
+ const [isLoading, setIsLoading] = useState(!initialTenant);
19
+ const [error, setError] = useState(null);
20
+ // Resolve tenant on mount
21
+ useEffect(() => {
22
+ if (initialTenant) {
23
+ setTenant(initialTenant);
24
+ setIsLoading(false);
25
+ return;
26
+ }
27
+ if (config?.defaultTenantId && fetchTenant) {
28
+ setIsLoading(true);
29
+ fetchTenant(config.defaultTenantId)
30
+ .then((resolved) => {
31
+ setTenant(resolved);
32
+ setError(null);
33
+ })
34
+ .catch((err) => {
35
+ setError(err instanceof Error ? err : new Error(String(err)));
36
+ })
37
+ .finally(() => {
38
+ setIsLoading(false);
39
+ });
40
+ }
41
+ else {
42
+ setIsLoading(false);
43
+ }
44
+ }, [initialTenant, config?.defaultTenantId, fetchTenant]);
45
+ const switchTenant = useCallback(async (tenantId) => {
46
+ if (!fetchTenant) {
47
+ throw new Error('fetchTenant is required to switch tenants');
48
+ }
49
+ setIsLoading(true);
50
+ try {
51
+ const resolved = await fetchTenant(tenantId);
52
+ setTenant(resolved);
53
+ setError(null);
54
+ }
55
+ catch (err) {
56
+ setError(err instanceof Error ? err : new Error(String(err)));
57
+ throw err;
58
+ }
59
+ finally {
60
+ setIsLoading(false);
61
+ }
62
+ }, [fetchTenant]);
63
+ const mergedBranding = useMemo(() => ({
64
+ ...DEFAULT_BRANDING,
65
+ ...defaultBranding,
66
+ ...tenant?.branding,
67
+ }), [defaultBranding, tenant?.branding]);
68
+ const value = useMemo(() => {
69
+ if (!tenant)
70
+ return null;
71
+ return {
72
+ tenant,
73
+ isTenantAdmin: false,
74
+ branding: mergedBranding,
75
+ features: tenant.features ?? {},
76
+ switchTenant,
77
+ isLoading,
78
+ error,
79
+ };
80
+ }, [tenant, mergedBranding, switchTenant, isLoading, error]);
81
+ // While loading or if no tenant, still render children (they can handle null context)
82
+ return _jsx(TenantCtx.Provider, { value: value, children: children });
83
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import type { TenantScopedQueryConfig } from '@object-ui/types';
9
+ export interface TenantScopedQueryProps {
10
+ /** Base query/filter */
11
+ filter?: Record<string, unknown>[];
12
+ /** Tenant ID to scope to */
13
+ tenantId: string;
14
+ /** Scoped query configuration */
15
+ config: TenantScopedQueryConfig;
16
+ /** Object name for exclusion check */
17
+ objectName?: string;
18
+ }
19
+ /**
20
+ * Applies tenant scoping to a query filter.
21
+ * Returns the original filter with tenant isolation applied.
22
+ */
23
+ export declare function TenantScopedQuery({ filter, tenantId, config, objectName, }: TenantScopedQueryProps): Record<string, unknown>[];
24
+ //# sourceMappingURL=TenantScopedQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TenantScopedQuery.d.ts","sourceRoot":"","sources":["../src/TenantScopedQuery.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,WAAW,sBAAsB;IACrC,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACnC,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,MAAM,EAAE,uBAAuB,CAAC;IAChC,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,MAAW,EACX,QAAQ,EACR,MAAM,EACN,UAAU,GACX,EAAE,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAkBpD"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * Applies tenant scoping to a query filter.
10
+ * Returns the original filter with tenant isolation applied.
11
+ */
12
+ export function TenantScopedQuery({ filter = [], tenantId, config, objectName, }) {
13
+ // Skip scoping for excluded objects
14
+ if (objectName && config.excludedObjects?.includes(objectName)) {
15
+ return filter;
16
+ }
17
+ if (!config.autoFilter) {
18
+ return filter;
19
+ }
20
+ // Add tenant filter condition
21
+ const tenantFilter = {
22
+ field: config.tenantField,
23
+ operator: '=',
24
+ value: tenantId,
25
+ };
26
+ return [...filter, tenantFilter];
27
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * @object-ui/tenant
10
+ *
11
+ * Multi-tenancy support for Object UI providing:
12
+ * - TenantProvider context for React apps
13
+ * - useTenant hook for accessing tenant context
14
+ * - Tenant isolation and scoped queries
15
+ * - Custom branding per tenant
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export { TenantProvider, type TenantProviderProps } from './TenantProvider';
20
+ export { useTenant } from './useTenant';
21
+ export { useTenantBranding } from './useTenantBranding';
22
+ export { TenantGuard, type TenantGuardProps } from './TenantGuard';
23
+ export { createTenantResolver, type TenantResolver } from './resolver';
24
+ export { TenantScopedQuery, type TenantScopedQueryProps } from './TenantScopedQuery';
25
+ export type { TenantConfig, TenantBranding, TenantLimits, TenantContext, TenantProviderConfig, TenantScopedQueryConfig, TenantIsolationStrategy, TenantStatus, TenantPlan, TenantResolutionStrategy, } from '@object-ui/types';
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAGrF,YAAY,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,YAAY,EACZ,UAAU,EACV,wBAAwB,GACzB,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * @object-ui/tenant
10
+ *
11
+ * Multi-tenancy support for Object UI providing:
12
+ * - TenantProvider context for React apps
13
+ * - useTenant hook for accessing tenant context
14
+ * - Tenant isolation and scoped queries
15
+ * - Custom branding per tenant
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export { TenantProvider } from './TenantProvider';
20
+ export { useTenant } from './useTenant';
21
+ export { useTenantBranding } from './useTenantBranding';
22
+ export { TenantGuard } from './TenantGuard';
23
+ export { createTenantResolver } from './resolver';
24
+ export { TenantScopedQuery } from './TenantScopedQuery';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import type { TenantResolutionStrategy } from '@object-ui/types';
9
+ export interface TenantResolver {
10
+ /** Resolve tenant ID from the current context */
11
+ resolve: () => string | null;
12
+ }
13
+ /**
14
+ * Creates a tenant resolver based on the specified strategy.
15
+ *
16
+ * @param strategy - How to extract the tenant identifier
17
+ * @param options - Strategy-specific options
18
+ * @returns A TenantResolver instance
19
+ */
20
+ export declare function createTenantResolver(strategy: TenantResolutionStrategy, options?: {
21
+ headerName?: string;
22
+ queryParam?: string;
23
+ cookieName?: string;
24
+ customResolver?: () => string | null;
25
+ }): TenantResolver;
26
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAEjE,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,OAAO,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,wBAAwB,EAClC,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACtC,GACA,cAAc,CA8DhB"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * Creates a tenant resolver based on the specified strategy.
10
+ *
11
+ * @param strategy - How to extract the tenant identifier
12
+ * @param options - Strategy-specific options
13
+ * @returns A TenantResolver instance
14
+ */
15
+ export function createTenantResolver(strategy, options) {
16
+ switch (strategy) {
17
+ case 'subdomain':
18
+ return {
19
+ resolve: () => {
20
+ if (typeof window === 'undefined')
21
+ return null;
22
+ const parts = window.location.hostname.split('.');
23
+ return parts.length > 2 ? parts[0] : null;
24
+ },
25
+ };
26
+ case 'path':
27
+ return {
28
+ resolve: () => {
29
+ if (typeof window === 'undefined')
30
+ return null;
31
+ const parts = window.location.pathname.split('/').filter(Boolean);
32
+ return parts.length > 0 ? parts[0] : null;
33
+ },
34
+ };
35
+ case 'header':
36
+ return {
37
+ resolve: () => null, // Headers are server-side only
38
+ };
39
+ case 'query':
40
+ return {
41
+ resolve: () => {
42
+ if (typeof window === 'undefined')
43
+ return null;
44
+ const params = new URLSearchParams(window.location.search);
45
+ return params.get(options?.queryParam ?? 'tenant');
46
+ },
47
+ };
48
+ case 'cookie':
49
+ return {
50
+ resolve: () => {
51
+ if (typeof document === 'undefined')
52
+ return null;
53
+ const name = options?.cookieName ?? 'tenant_id';
54
+ const cookies = document.cookie.split('; ');
55
+ for (const cookie of cookies) {
56
+ const eqIndex = cookie.indexOf('=');
57
+ if (eqIndex === -1)
58
+ continue;
59
+ const key = cookie.substring(0, eqIndex);
60
+ if (key === name) {
61
+ return decodeURIComponent(cookie.substring(eqIndex + 1));
62
+ }
63
+ }
64
+ return null;
65
+ },
66
+ };
67
+ case 'custom':
68
+ return {
69
+ resolve: () => options?.customResolver?.() ?? null,
70
+ };
71
+ default:
72
+ return {
73
+ resolve: () => null,
74
+ };
75
+ }
76
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import { type TenantContextValue } from './TenantContext';
9
+ /**
10
+ * Hook to access the current tenant context.
11
+ * Must be used within a TenantProvider.
12
+ *
13
+ * @returns Tenant context value or null if no tenant is configured
14
+ */
15
+ export declare function useTenant(): TenantContextValue | null;
16
+ //# sourceMappingURL=useTenant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTenant.d.ts","sourceRoot":"","sources":["../src/useTenant.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAa,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;;;GAKG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,GAAG,IAAI,CAErD"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import { useContext } from 'react';
9
+ import { TenantCtx } from './TenantContext';
10
+ /**
11
+ * Hook to access the current tenant context.
12
+ * Must be used within a TenantProvider.
13
+ *
14
+ * @returns Tenant context value or null if no tenant is configured
15
+ */
16
+ export function useTenant() {
17
+ return useContext(TenantCtx);
18
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import type { TenantBranding } from '@object-ui/types';
9
+ /**
10
+ * Hook to access resolved tenant branding.
11
+ * Returns default branding if no tenant is configured.
12
+ */
13
+ export declare function useTenantBranding(): TenantBranding;
14
+ //# sourceMappingURL=useTenantBranding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTenantBranding.d.ts","sourceRoot":"","sources":["../src/useTenantBranding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAYlD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import { useMemo } from 'react';
9
+ import { useTenant } from './useTenant';
10
+ /**
11
+ * Hook to access resolved tenant branding.
12
+ * Returns default branding if no tenant is configured.
13
+ */
14
+ export function useTenantBranding() {
15
+ const tenantCtx = useTenant();
16
+ return useMemo(() => tenantCtx?.branding ?? {
17
+ companyName: 'ObjectUI',
18
+ primaryColor: '#3b82f6',
19
+ secondaryColor: '#64748b',
20
+ }, [tenantCtx?.branding]);
21
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@object-ui/tenant",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "description": "Multi-tenancy support for Object UI with tenant isolation, scoped queries, and custom branding.",
7
+ "homepage": "https://www.objectui.org",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/objectstack-ai/objectui.git",
11
+ "directory": "packages/tenant"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "peerDependencies": {
26
+ "react": "^18.0.0 || ^19.0.0"
27
+ },
28
+ "dependencies": {
29
+ "@object-ui/types": "0.5.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/react": "^19.2.13",
33
+ "react": "^19.1.0",
34
+ "typescript": "^5.9.3",
35
+ "vitest": "^4.0.18"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "clean": "rm -rf dist",
40
+ "test": "vitest run",
41
+ "type-check": "tsc --noEmit",
42
+ "lint": "eslint ."
43
+ }
44
+ }