@open-mercato/core 0.4.5-develop-0b66ecfdd4 → 0.4.5-develop-2289152f60
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/dist/modules/directory/utils/organizationScope.js +1 -34
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/directory/utils/scopeCookies.js +39 -0
- package/dist/modules/directory/utils/scopeCookies.js.map +7 -0
- package/package.json +2 -2
- package/src/modules/directory/utils/organizationScope.ts +3 -36
- package/src/modules/directory/utils/scopeCookies.ts +36 -0
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { Organization } from "@open-mercato/core/modules/directory/data/entities";
|
|
2
2
|
import { isAllOrganizationsSelection } from "@open-mercato/core/modules/directory/constants";
|
|
3
|
-
|
|
4
|
-
if (!header) return null;
|
|
5
|
-
const parts = header.split(";");
|
|
6
|
-
for (const part of parts) {
|
|
7
|
-
const trimmed = part.trim();
|
|
8
|
-
if (trimmed.startsWith("om_selected_org=")) {
|
|
9
|
-
const raw = trimmed.slice("om_selected_org=".length);
|
|
10
|
-
try {
|
|
11
|
-
const decoded = decodeURIComponent(raw);
|
|
12
|
-
return decoded || null;
|
|
13
|
-
} catch {
|
|
14
|
-
return raw || null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
3
|
+
import { parseSelectedOrganizationCookie, parseSelectedTenantCookie } from "./scopeCookies.js";
|
|
20
4
|
function getSelectedOrganizationFromRequest(req) {
|
|
21
5
|
const cookieContainer = req.cookies;
|
|
22
6
|
if (cookieContainer && typeof cookieContainer.get === "function") {
|
|
@@ -27,23 +11,6 @@ function getSelectedOrganizationFromRequest(req) {
|
|
|
27
11
|
const header = typeof headerContainer?.get === "function" ? headerContainer.get("cookie") : null;
|
|
28
12
|
return parseSelectedOrganizationCookie(header);
|
|
29
13
|
}
|
|
30
|
-
function parseSelectedTenantCookie(header) {
|
|
31
|
-
if (!header) return null;
|
|
32
|
-
const parts = header.split(";");
|
|
33
|
-
for (const part of parts) {
|
|
34
|
-
const trimmed = part.trim();
|
|
35
|
-
if (trimmed.startsWith("om_selected_tenant=")) {
|
|
36
|
-
const raw = trimmed.slice("om_selected_tenant=".length);
|
|
37
|
-
try {
|
|
38
|
-
const decoded = decodeURIComponent(raw);
|
|
39
|
-
return decoded || null;
|
|
40
|
-
} catch {
|
|
41
|
-
return raw || null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
14
|
function getSelectedTenantFromRequest(req) {
|
|
48
15
|
const cookieContainer = req.cookies;
|
|
49
16
|
if (cookieContainer && typeof cookieContainer.get === "function") {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/directory/utils/organizationScope.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { FilterQuery } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { isAllOrganizationsSelection } from '@open-mercato/core/modules/directory/constants'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\n\nexport type OrganizationScope = {\n selectedId: string | null\n filterIds: string[] | null\n allowedIds: string[] | null\n tenantId: string | null\n}\n\nexport function parseSelectedOrganizationCookie(header: string | null | undefined): string | null {\n if (!header) return null\n const parts = header.split(';')\n for (const part of parts) {\n const trimmed = part.trim()\n if (trimmed.startsWith('om_selected_org=')) {\n const raw = trimmed.slice('om_selected_org='.length)\n try {\n const decoded = decodeURIComponent(raw)\n return decoded || null\n } catch {\n return raw || null\n }\n }\n }\n return null\n}\n\nexport function getSelectedOrganizationFromRequest(req: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } }): string | null {\n const cookieContainer = (req as { cookies?: { get: (name: string) => { value: string } | undefined } }).cookies\n if (cookieContainer && typeof cookieContainer.get === 'function') {\n const val = cookieContainer.get('om_selected_org')?.value\n return val ?? null\n }\n const headerContainer = (req as { headers?: { get(name: string): string | null } }).headers\n const header = typeof headerContainer?.get === 'function' ? headerContainer.get('cookie') : null\n return parseSelectedOrganizationCookie(header)\n}\n\nexport function parseSelectedTenantCookie(header: string | null | undefined): string | null {\n if (!header) return null\n const parts = header.split(';')\n for (const part of parts) {\n const trimmed = part.trim()\n if (trimmed.startsWith('om_selected_tenant=')) {\n const raw = trimmed.slice('om_selected_tenant='.length)\n try {\n const decoded = decodeURIComponent(raw)\n return decoded || null\n } catch {\n return raw || null\n }\n }\n }\n return null\n}\n\nexport function getSelectedTenantFromRequest(\n req: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } },\n): string | null {\n const cookieContainer = (req as { cookies?: { get: (name: string) => { value: string } | undefined } }).cookies\n if (cookieContainer && typeof cookieContainer.get === 'function') {\n const val = cookieContainer.get('om_selected_tenant')?.value\n return val ?? null\n }\n const headerContainer = (req as { headers?: { get(name: string): string | null } }).headers\n const header = typeof headerContainer?.get === 'function' ? headerContainer.get('cookie') : null\n return parseSelectedTenantCookie(header)\n}\n\nasync function collectWithDescendants(em: EntityManager, tenantId: string, ids: string[]): Promise<Set<string>> {\n if (!ids.length) return new Set()\n const unique = Array.from(new Set(\n ids.filter((value): value is string => {\n if (!value) return false\n if (isAllOrganizationsSelection(value)) return false\n return true\n })\n ))\n if (!unique.length) return new Set()\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n id: { $in: unique },\n deletedAt: null,\n }\n const orgs = await em.find(Organization, filter)\n const set = new Set<string>()\n for (const org of orgs) {\n const id = String(org.id)\n set.add(id)\n if (Array.isArray(org.descendantIds)) {\n for (const desc of org.descendantIds) set.add(String(desc))\n }\n }\n return set\n}\n\nexport async function resolveOrganizationScope({\n em,\n rbac,\n auth,\n selectedId,\n tenantId: tenantIdOverride,\n}: {\n em: EntityManager\n rbac: RbacService\n auth: AuthContext\n selectedId?: string | null\n tenantId?: string | null\n}): Promise<OrganizationScope> {\n if (!auth || !auth.sub) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n const actorTenantId = typeof auth.tenantId === 'string' && auth.tenantId.trim().length > 0 ? auth.tenantId.trim() : null\n const candidateTenantId = typeof tenantIdOverride === 'string' && tenantIdOverride.trim().length > 0\n ? tenantIdOverride.trim()\n : tenantIdOverride === null\n ? null\n : actorTenantId\n if (!candidateTenantId) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n const usingOverride = candidateTenantId !== actorTenantId\n const isSuperAdminActor = auth.isSuperAdmin === true\n const tenantId = usingOverride && actorTenantId && !isSuperAdminActor ? actorTenantId : candidateTenantId\n if (!tenantId) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n const explicitAllSelection = selectedId === null\n const normalizedSelectedId = typeof selectedId === 'string' && isAllOrganizationsSelection(selectedId)\n ? null\n : (selectedId ?? null)\n const contextOrgId = actorTenantId && actorTenantId === tenantId ? auth.orgId ?? null : null\n const acl = await rbac.loadAcl(auth.sub, { tenantId, organizationId: contextOrgId })\n const aclIsSuperAdmin = acl?.isSuperAdmin === true\n const effectiveSuperAdmin = aclIsSuperAdmin || isSuperAdminActor\n const rawAccessible = effectiveSuperAdmin\n ? null\n : Array.isArray(acl?.organizations)\n ? acl.organizations.filter(Boolean)\n : null\n const accessibleList = effectiveSuperAdmin\n ? null\n : rawAccessible && rawAccessible.some((value) => typeof value === 'string' && isAllOrganizationsSelection(value))\n ? null\n : rawAccessible?.filter((value): value is string => typeof value === 'string' && !isAllOrganizationsSelection(value)) ?? null\n\n const accountOrgId = actorTenantId && actorTenantId === tenantId ? auth.orgId ?? null : null\n const fallbackOrgId = accountOrgId ?? null\n let fallbackSet: Set<string> | null = null\n const loadFallbackSet = async (): Promise<Set<string> | null> => {\n if (!fallbackOrgId) return null\n if (!fallbackSet) {\n fallbackSet = await collectWithDescendants(em, tenantId, [fallbackOrgId])\n }\n return fallbackSet\n }\n\n let allowedSet: Set<string> | null = null\n if (accessibleList === null) {\n allowedSet = null\n } else if (accessibleList.length === 0) {\n allowedSet = new Set()\n } else {\n allowedSet = await collectWithDescendants(em, tenantId, accessibleList)\n }\n\n if (allowedSet && allowedSet.size === 0 && fallbackOrgId) {\n const computed = await loadFallbackSet()\n if (computed && computed.size > 0) {\n allowedSet = computed\n }\n }\n\n const initialSelected = normalizedSelectedId ?? (explicitAllSelection && effectiveSuperAdmin ? null : accountOrgId ?? null)\n let effectiveSelected: string | null = null\n if (initialSelected) {\n if (allowedSet === null || allowedSet.has(initialSelected)) {\n effectiveSelected = initialSelected\n }\n }\n\n let filterSet: Set<string> | null = null\n if (effectiveSelected) {\n filterSet = await collectWithDescendants(em, tenantId, [effectiveSelected])\n } else if (allowedSet !== null) {\n filterSet = allowedSet\n } else if (explicitAllSelection && effectiveSuperAdmin) {\n filterSet = null\n } else if (auth.orgId) {\n filterSet = await loadFallbackSet()\n }\n\n if ((!filterSet || filterSet.size === 0) && fallbackOrgId && !(explicitAllSelection && effectiveSuperAdmin)) {\n const computed = await loadFallbackSet()\n if (computed && computed.size > 0) {\n filterSet = computed\n if (!effectiveSelected) {\n effectiveSelected = fallbackOrgId\n }\n }\n }\n\n return {\n selectedId: effectiveSelected,\n filterIds: filterSet ? Array.from(filterSet) : null,\n allowedIds: allowedSet ? Array.from(allowedSet) : null,\n tenantId,\n }\n}\n\nexport async function resolveOrganizationScopeForRequest({\n container,\n auth,\n request,\n selectedId,\n tenantId: tenantOverride,\n}: {\n container: AwilixContainer\n auth: AuthContext | null | undefined\n request?: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } }\n selectedId?: string | null\n tenantId?: string | null\n}): Promise<OrganizationScope> {\n if (!auth || !auth.sub) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n\n let em: EntityManager | null = null\n let rbac: RbacService | null = null\n try { em = container.resolve<EntityManager>('em') } catch { em = null }\n try { rbac = container.resolve<RbacService>('rbacService') } catch { rbac = null }\n if (!em || !rbac) {\n const fallbackSelected = selectedId ?? auth.orgId ?? null\n return {\n selectedId: fallbackSelected,\n filterIds: fallbackSelected ? [fallbackSelected] : null,\n allowedIds: fallbackSelected ? [fallbackSelected] : null,\n tenantId: auth.tenantId ?? null,\n }\n }\n\n const normalizeString = (value: unknown): string | null => {\n if (typeof value === 'string' && value.trim().length > 0) return value.trim()\n return null\n }\n\n const actorTenantField = (auth as { actorTenantId?: string | null }).actorTenantId\n const actorTenant = actorTenantField === undefined\n ? normalizeString(auth.tenantId)\n : actorTenantField === null\n ? null\n : normalizeString(actorTenantField)\n const actorOrgField = (auth as { actorOrgId?: string | null }).actorOrgId\n const actorOrgId = actorOrgField === undefined\n ? normalizeString(auth.orgId)\n : actorOrgField === null\n ? null\n : normalizeString(actorOrgField)\n\n const cookieTenant = request ? getSelectedTenantFromRequest(request) : null\n const requestedTenant =\n tenantOverride !== undefined\n ? tenantOverride\n : cookieTenant !== undefined\n ? cookieTenant\n : undefined\n const requestedTenantId = typeof requestedTenant === 'string' && requestedTenant.trim().length > 0 ? requestedTenant.trim() : null\n const isSuperAdminActor = auth.isSuperAdmin === true\n let effectiveTenantId = requestedTenantId ?? actorTenant ?? null\n if (actorTenant && effectiveTenantId && effectiveTenantId !== actorTenant && !isSuperAdminActor) {\n effectiveTenantId = actorTenant\n }\n if (!effectiveTenantId) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n\n const scopedAuth = {\n ...auth,\n tenantId: effectiveTenantId,\n orgId: actorTenant && actorTenant === effectiveTenantId ? actorOrgId ?? null : null,\n }\n\n const rawSelected = selectedId !== undefined ? selectedId : (request ? getSelectedOrganizationFromRequest(request) : null)\n const reqSelected = typeof rawSelected === 'string' && isAllOrganizationsSelection(rawSelected) ? null : rawSelected\n const baseScope = await resolveOrganizationScope({\n em,\n rbac,\n auth: scopedAuth,\n selectedId: reqSelected,\n tenantId: effectiveTenantId,\n })\n\n return baseScope\n}\n\nexport type FeatureCheckContext = {\n organizationId: string | null\n scope: OrganizationScope\n allowedOrganizationIds: string[] | null\n}\n\nexport async function resolveFeatureCheckContext({\n container,\n auth,\n request,\n selectedId,\n tenantId,\n}: {\n container: AwilixContainer\n auth: AuthContext | null | undefined\n request?: Request | { cookies?: { get: (name: string) => { value: string } | undefined } }\n selectedId?: string | null\n tenantId?: string | null\n}): Promise<FeatureCheckContext> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request, selectedId, tenantId })\n const allowedOrganizationIds = scope.allowedIds ?? null\n const authOrgId = auth?.orgId ?? null\n const organizationId =\n scope.selectedId\n ?? (authOrgId && (!Array.isArray(allowedOrganizationIds) || allowedOrganizationIds.includes(authOrgId)) ? authOrgId : null)\n ?? (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length ? allowedOrganizationIds[0] : null)\n\n return { organizationId, scope, allowedOrganizationIds }\n}\n"],
|
|
5
|
-
"mappings": "AAGA,SAAS,oBAAoB;AAC7B,SAAS,mCAAmC;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { FilterQuery } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { isAllOrganizationsSelection } from '@open-mercato/core/modules/directory/constants'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { parseSelectedOrganizationCookie, parseSelectedTenantCookie } from './scopeCookies'\n\nexport { parseSelectedOrganizationCookie, parseSelectedTenantCookie }\n\nexport type OrganizationScope = {\n selectedId: string | null\n filterIds: string[] | null\n allowedIds: string[] | null\n tenantId: string | null\n}\n\nexport function getSelectedOrganizationFromRequest(req: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } }): string | null {\n const cookieContainer = (req as { cookies?: { get: (name: string) => { value: string } | undefined } }).cookies\n if (cookieContainer && typeof cookieContainer.get === 'function') {\n const val = cookieContainer.get('om_selected_org')?.value\n return val ?? null\n }\n const headerContainer = (req as { headers?: { get(name: string): string | null } }).headers\n const header = typeof headerContainer?.get === 'function' ? headerContainer.get('cookie') : null\n return parseSelectedOrganizationCookie(header)\n}\n\nexport function getSelectedTenantFromRequest(\n req: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } },\n): string | null {\n const cookieContainer = (req as { cookies?: { get: (name: string) => { value: string } | undefined } }).cookies\n if (cookieContainer && typeof cookieContainer.get === 'function') {\n const val = cookieContainer.get('om_selected_tenant')?.value\n return val ?? null\n }\n const headerContainer = (req as { headers?: { get(name: string): string | null } }).headers\n const header = typeof headerContainer?.get === 'function' ? headerContainer.get('cookie') : null\n return parseSelectedTenantCookie(header)\n}\n\nasync function collectWithDescendants(em: EntityManager, tenantId: string, ids: string[]): Promise<Set<string>> {\n if (!ids.length) return new Set()\n const unique = Array.from(new Set(\n ids.filter((value): value is string => {\n if (!value) return false\n if (isAllOrganizationsSelection(value)) return false\n return true\n })\n ))\n if (!unique.length) return new Set()\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n id: { $in: unique },\n deletedAt: null,\n }\n const orgs = await em.find(Organization, filter)\n const set = new Set<string>()\n for (const org of orgs) {\n const id = String(org.id)\n set.add(id)\n if (Array.isArray(org.descendantIds)) {\n for (const desc of org.descendantIds) set.add(String(desc))\n }\n }\n return set\n}\n\nexport async function resolveOrganizationScope({\n em,\n rbac,\n auth,\n selectedId,\n tenantId: tenantIdOverride,\n}: {\n em: EntityManager\n rbac: RbacService\n auth: AuthContext\n selectedId?: string | null\n tenantId?: string | null\n}): Promise<OrganizationScope> {\n if (!auth || !auth.sub) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n const actorTenantId = typeof auth.tenantId === 'string' && auth.tenantId.trim().length > 0 ? auth.tenantId.trim() : null\n const candidateTenantId = typeof tenantIdOverride === 'string' && tenantIdOverride.trim().length > 0\n ? tenantIdOverride.trim()\n : tenantIdOverride === null\n ? null\n : actorTenantId\n if (!candidateTenantId) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n const usingOverride = candidateTenantId !== actorTenantId\n const isSuperAdminActor = auth.isSuperAdmin === true\n const tenantId = usingOverride && actorTenantId && !isSuperAdminActor ? actorTenantId : candidateTenantId\n if (!tenantId) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n const explicitAllSelection = selectedId === null\n const normalizedSelectedId = typeof selectedId === 'string' && isAllOrganizationsSelection(selectedId)\n ? null\n : (selectedId ?? null)\n const contextOrgId = actorTenantId && actorTenantId === tenantId ? auth.orgId ?? null : null\n const acl = await rbac.loadAcl(auth.sub, { tenantId, organizationId: contextOrgId })\n const aclIsSuperAdmin = acl?.isSuperAdmin === true\n const effectiveSuperAdmin = aclIsSuperAdmin || isSuperAdminActor\n const rawAccessible = effectiveSuperAdmin\n ? null\n : Array.isArray(acl?.organizations)\n ? acl.organizations.filter(Boolean)\n : null\n const accessibleList = effectiveSuperAdmin\n ? null\n : rawAccessible && rawAccessible.some((value) => typeof value === 'string' && isAllOrganizationsSelection(value))\n ? null\n : rawAccessible?.filter((value): value is string => typeof value === 'string' && !isAllOrganizationsSelection(value)) ?? null\n\n const accountOrgId = actorTenantId && actorTenantId === tenantId ? auth.orgId ?? null : null\n const fallbackOrgId = accountOrgId ?? null\n let fallbackSet: Set<string> | null = null\n const loadFallbackSet = async (): Promise<Set<string> | null> => {\n if (!fallbackOrgId) return null\n if (!fallbackSet) {\n fallbackSet = await collectWithDescendants(em, tenantId, [fallbackOrgId])\n }\n return fallbackSet\n }\n\n let allowedSet: Set<string> | null = null\n if (accessibleList === null) {\n allowedSet = null\n } else if (accessibleList.length === 0) {\n allowedSet = new Set()\n } else {\n allowedSet = await collectWithDescendants(em, tenantId, accessibleList)\n }\n\n if (allowedSet && allowedSet.size === 0 && fallbackOrgId) {\n const computed = await loadFallbackSet()\n if (computed && computed.size > 0) {\n allowedSet = computed\n }\n }\n\n const initialSelected = normalizedSelectedId ?? (explicitAllSelection && effectiveSuperAdmin ? null : accountOrgId ?? null)\n let effectiveSelected: string | null = null\n if (initialSelected) {\n if (allowedSet === null || allowedSet.has(initialSelected)) {\n effectiveSelected = initialSelected\n }\n }\n\n let filterSet: Set<string> | null = null\n if (effectiveSelected) {\n filterSet = await collectWithDescendants(em, tenantId, [effectiveSelected])\n } else if (allowedSet !== null) {\n filterSet = allowedSet\n } else if (explicitAllSelection && effectiveSuperAdmin) {\n filterSet = null\n } else if (auth.orgId) {\n filterSet = await loadFallbackSet()\n }\n\n if ((!filterSet || filterSet.size === 0) && fallbackOrgId && !(explicitAllSelection && effectiveSuperAdmin)) {\n const computed = await loadFallbackSet()\n if (computed && computed.size > 0) {\n filterSet = computed\n if (!effectiveSelected) {\n effectiveSelected = fallbackOrgId\n }\n }\n }\n\n return {\n selectedId: effectiveSelected,\n filterIds: filterSet ? Array.from(filterSet) : null,\n allowedIds: allowedSet ? Array.from(allowedSet) : null,\n tenantId,\n }\n}\n\nexport async function resolveOrganizationScopeForRequest({\n container,\n auth,\n request,\n selectedId,\n tenantId: tenantOverride,\n}: {\n container: AwilixContainer\n auth: AuthContext | null | undefined\n request?: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } }\n selectedId?: string | null\n tenantId?: string | null\n}): Promise<OrganizationScope> {\n if (!auth || !auth.sub) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n\n let em: EntityManager | null = null\n let rbac: RbacService | null = null\n try { em = container.resolve<EntityManager>('em') } catch { em = null }\n try { rbac = container.resolve<RbacService>('rbacService') } catch { rbac = null }\n if (!em || !rbac) {\n const fallbackSelected = selectedId ?? auth.orgId ?? null\n return {\n selectedId: fallbackSelected,\n filterIds: fallbackSelected ? [fallbackSelected] : null,\n allowedIds: fallbackSelected ? [fallbackSelected] : null,\n tenantId: auth.tenantId ?? null,\n }\n }\n\n const normalizeString = (value: unknown): string | null => {\n if (typeof value === 'string' && value.trim().length > 0) return value.trim()\n return null\n }\n\n const actorTenantField = (auth as { actorTenantId?: string | null }).actorTenantId\n const actorTenant = actorTenantField === undefined\n ? normalizeString(auth.tenantId)\n : actorTenantField === null\n ? null\n : normalizeString(actorTenantField)\n const actorOrgField = (auth as { actorOrgId?: string | null }).actorOrgId\n const actorOrgId = actorOrgField === undefined\n ? normalizeString(auth.orgId)\n : actorOrgField === null\n ? null\n : normalizeString(actorOrgField)\n\n const cookieTenant = request ? getSelectedTenantFromRequest(request) : null\n const requestedTenant =\n tenantOverride !== undefined\n ? tenantOverride\n : cookieTenant !== undefined\n ? cookieTenant\n : undefined\n const requestedTenantId = typeof requestedTenant === 'string' && requestedTenant.trim().length > 0 ? requestedTenant.trim() : null\n const isSuperAdminActor = auth.isSuperAdmin === true\n let effectiveTenantId = requestedTenantId ?? actorTenant ?? null\n if (actorTenant && effectiveTenantId && effectiveTenantId !== actorTenant && !isSuperAdminActor) {\n effectiveTenantId = actorTenant\n }\n if (!effectiveTenantId) {\n return { selectedId: null, filterIds: null, allowedIds: null, tenantId: null }\n }\n\n const scopedAuth = {\n ...auth,\n tenantId: effectiveTenantId,\n orgId: actorTenant && actorTenant === effectiveTenantId ? actorOrgId ?? null : null,\n }\n\n const rawSelected = selectedId !== undefined ? selectedId : (request ? getSelectedOrganizationFromRequest(request) : null)\n const reqSelected = typeof rawSelected === 'string' && isAllOrganizationsSelection(rawSelected) ? null : rawSelected\n const baseScope = await resolveOrganizationScope({\n em,\n rbac,\n auth: scopedAuth,\n selectedId: reqSelected,\n tenantId: effectiveTenantId,\n })\n\n return baseScope\n}\n\nexport type FeatureCheckContext = {\n organizationId: string | null\n scope: OrganizationScope\n allowedOrganizationIds: string[] | null\n}\n\nexport async function resolveFeatureCheckContext({\n container,\n auth,\n request,\n selectedId,\n tenantId,\n}: {\n container: AwilixContainer\n auth: AuthContext | null | undefined\n request?: Request | { cookies?: { get: (name: string) => { value: string } | undefined } }\n selectedId?: string | null\n tenantId?: string | null\n}): Promise<FeatureCheckContext> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request, selectedId, tenantId })\n const allowedOrganizationIds = scope.allowedIds ?? null\n const authOrgId = auth?.orgId ?? null\n const organizationId =\n scope.selectedId\n ?? (authOrgId && (!Array.isArray(allowedOrganizationIds) || allowedOrganizationIds.includes(authOrgId)) ? authOrgId : null)\n ?? (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length ? allowedOrganizationIds[0] : null)\n\n return { organizationId, scope, allowedOrganizationIds }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
function parseSelectedOrganizationCookie(header) {
|
|
2
|
+
if (!header) return null;
|
|
3
|
+
const parts = header.split(";");
|
|
4
|
+
for (const part of parts) {
|
|
5
|
+
const trimmed = part.trim();
|
|
6
|
+
if (trimmed.startsWith("om_selected_org=")) {
|
|
7
|
+
const raw = trimmed.slice("om_selected_org=".length);
|
|
8
|
+
try {
|
|
9
|
+
const decoded = decodeURIComponent(raw);
|
|
10
|
+
return decoded || null;
|
|
11
|
+
} catch {
|
|
12
|
+
return raw || null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
function parseSelectedTenantCookie(header) {
|
|
19
|
+
if (!header) return null;
|
|
20
|
+
const parts = header.split(";");
|
|
21
|
+
for (const part of parts) {
|
|
22
|
+
const trimmed = part.trim();
|
|
23
|
+
if (trimmed.startsWith("om_selected_tenant=")) {
|
|
24
|
+
const raw = trimmed.slice("om_selected_tenant=".length);
|
|
25
|
+
try {
|
|
26
|
+
const decoded = decodeURIComponent(raw);
|
|
27
|
+
return decoded || null;
|
|
28
|
+
} catch {
|
|
29
|
+
return raw || null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
parseSelectedOrganizationCookie,
|
|
37
|
+
parseSelectedTenantCookie
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=scopeCookies.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/directory/utils/scopeCookies.ts"],
|
|
4
|
+
"sourcesContent": ["export function parseSelectedOrganizationCookie(header: string | null | undefined): string | null {\n if (!header) return null\n const parts = header.split(';')\n for (const part of parts) {\n const trimmed = part.trim()\n if (trimmed.startsWith('om_selected_org=')) {\n const raw = trimmed.slice('om_selected_org='.length)\n try {\n const decoded = decodeURIComponent(raw)\n return decoded || null\n } catch {\n return raw || null\n }\n }\n }\n return null\n}\n\nexport function parseSelectedTenantCookie(header: string | null | undefined): string | null {\n if (!header) return null\n const parts = header.split(';')\n for (const part of parts) {\n const trimmed = part.trim()\n if (trimmed.startsWith('om_selected_tenant=')) {\n const raw = trimmed.slice('om_selected_tenant='.length)\n try {\n const decoded = decodeURIComponent(raw)\n return decoded || null\n } catch {\n return raw || null\n }\n }\n }\n return null\n}\n\n"],
|
|
5
|
+
"mappings": "AAAO,SAAS,gCAAgC,QAAkD;AAChG,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,WAAW,kBAAkB,GAAG;AAC1C,YAAM,MAAM,QAAQ,MAAM,mBAAmB,MAAM;AACnD,UAAI;AACF,cAAM,UAAU,mBAAmB,GAAG;AACtC,eAAO,WAAW;AAAA,MACpB,QAAQ;AACN,eAAO,OAAO;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,0BAA0B,QAAkD;AAC1F,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,WAAW,qBAAqB,GAAG;AAC7C,YAAM,MAAM,QAAQ,MAAM,sBAAsB,MAAM;AACtD,UAAI;AACF,cAAM,UAAU,mBAAmB,GAAG;AACtC,eAAO,WAAW;AAAA,MACpB,QAAQ;AACN,eAAO,OAAO;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.4.5-develop-
|
|
3
|
+
"version": "0.4.5-develop-2289152f60",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
}
|
|
208
208
|
},
|
|
209
209
|
"dependencies": {
|
|
210
|
-
"@open-mercato/shared": "0.4.5-develop-
|
|
210
|
+
"@open-mercato/shared": "0.4.5-develop-2289152f60",
|
|
211
211
|
"@types/semver": "^7.5.8",
|
|
212
212
|
"@xyflow/react": "^12.6.0",
|
|
213
213
|
"ai": "^6.0.0",
|
|
@@ -5,6 +5,9 @@ import { Organization } from '@open-mercato/core/modules/directory/data/entities
|
|
|
5
5
|
import { isAllOrganizationsSelection } from '@open-mercato/core/modules/directory/constants'
|
|
6
6
|
import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
|
|
7
7
|
import type { AuthContext } from '@open-mercato/shared/lib/auth/server'
|
|
8
|
+
import { parseSelectedOrganizationCookie, parseSelectedTenantCookie } from './scopeCookies'
|
|
9
|
+
|
|
10
|
+
export { parseSelectedOrganizationCookie, parseSelectedTenantCookie }
|
|
8
11
|
|
|
9
12
|
export type OrganizationScope = {
|
|
10
13
|
selectedId: string | null
|
|
@@ -13,24 +16,6 @@ export type OrganizationScope = {
|
|
|
13
16
|
tenantId: string | null
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
export function parseSelectedOrganizationCookie(header: string | null | undefined): string | null {
|
|
17
|
-
if (!header) return null
|
|
18
|
-
const parts = header.split(';')
|
|
19
|
-
for (const part of parts) {
|
|
20
|
-
const trimmed = part.trim()
|
|
21
|
-
if (trimmed.startsWith('om_selected_org=')) {
|
|
22
|
-
const raw = trimmed.slice('om_selected_org='.length)
|
|
23
|
-
try {
|
|
24
|
-
const decoded = decodeURIComponent(raw)
|
|
25
|
-
return decoded || null
|
|
26
|
-
} catch {
|
|
27
|
-
return raw || null
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return null
|
|
32
|
-
}
|
|
33
|
-
|
|
34
19
|
export function getSelectedOrganizationFromRequest(req: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } }): string | null {
|
|
35
20
|
const cookieContainer = (req as { cookies?: { get: (name: string) => { value: string } | undefined } }).cookies
|
|
36
21
|
if (cookieContainer && typeof cookieContainer.get === 'function') {
|
|
@@ -42,24 +27,6 @@ export function getSelectedOrganizationFromRequest(req: Request | { cookies?: {
|
|
|
42
27
|
return parseSelectedOrganizationCookie(header)
|
|
43
28
|
}
|
|
44
29
|
|
|
45
|
-
export function parseSelectedTenantCookie(header: string | null | undefined): string | null {
|
|
46
|
-
if (!header) return null
|
|
47
|
-
const parts = header.split(';')
|
|
48
|
-
for (const part of parts) {
|
|
49
|
-
const trimmed = part.trim()
|
|
50
|
-
if (trimmed.startsWith('om_selected_tenant=')) {
|
|
51
|
-
const raw = trimmed.slice('om_selected_tenant='.length)
|
|
52
|
-
try {
|
|
53
|
-
const decoded = decodeURIComponent(raw)
|
|
54
|
-
return decoded || null
|
|
55
|
-
} catch {
|
|
56
|
-
return raw || null
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return null
|
|
61
|
-
}
|
|
62
|
-
|
|
63
30
|
export function getSelectedTenantFromRequest(
|
|
64
31
|
req: Request | { cookies?: { get: (name: string) => { value: string } | undefined }; headers?: { get(name: string): string | null } },
|
|
65
32
|
): string | null {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function parseSelectedOrganizationCookie(header: string | null | undefined): string | null {
|
|
2
|
+
if (!header) return null
|
|
3
|
+
const parts = header.split(';')
|
|
4
|
+
for (const part of parts) {
|
|
5
|
+
const trimmed = part.trim()
|
|
6
|
+
if (trimmed.startsWith('om_selected_org=')) {
|
|
7
|
+
const raw = trimmed.slice('om_selected_org='.length)
|
|
8
|
+
try {
|
|
9
|
+
const decoded = decodeURIComponent(raw)
|
|
10
|
+
return decoded || null
|
|
11
|
+
} catch {
|
|
12
|
+
return raw || null
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function parseSelectedTenantCookie(header: string | null | undefined): string | null {
|
|
20
|
+
if (!header) return null
|
|
21
|
+
const parts = header.split(';')
|
|
22
|
+
for (const part of parts) {
|
|
23
|
+
const trimmed = part.trim()
|
|
24
|
+
if (trimmed.startsWith('om_selected_tenant=')) {
|
|
25
|
+
const raw = trimmed.slice('om_selected_tenant='.length)
|
|
26
|
+
try {
|
|
27
|
+
const decoded = decodeURIComponent(raw)
|
|
28
|
+
return decoded || null
|
|
29
|
+
} catch {
|
|
30
|
+
return raw || null
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|