@eminuckan/spine 0.2.4 → 0.3.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.
Files changed (112) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/CODE_OF_CONDUCT.md +39 -0
  3. package/CONTRIBUTING.md +78 -0
  4. package/MAINTAINERS.md +43 -0
  5. package/README.md +66 -49
  6. package/ROADMAP.md +58 -0
  7. package/SECURITY.md +37 -0
  8. package/dist/access/evaluator.d.ts.map +1 -1
  9. package/dist/access/index.js +1 -1
  10. package/dist/access/types.d.ts +10 -2
  11. package/dist/access/types.d.ts.map +1 -1
  12. package/dist/{access-DlAqsVGQ.js → access-CGrsDMwu.js} +9 -7
  13. package/dist/access-CGrsDMwu.js.map +1 -0
  14. package/dist/api-client/api-config.server.d.ts +27 -0
  15. package/dist/api-client/api-config.server.d.ts.map +1 -1
  16. package/dist/api-client/error-codes.d.ts +6 -31
  17. package/dist/api-client/error-codes.d.ts.map +1 -1
  18. package/dist/api-client/index.js +2 -2
  19. package/dist/api-client/server.d.ts +1 -1
  20. package/dist/api-client/server.d.ts.map +1 -1
  21. package/dist/api-client/server.js +3 -3
  22. package/dist/{api-client-CZapXIF8.js → api-client-CgZUMukO.js} +9 -26
  23. package/dist/api-client-CgZUMukO.js.map +1 -0
  24. package/dist/auth/auth.server.d.ts.map +1 -1
  25. package/dist/auth/authorization-parameters.d.ts +5 -0
  26. package/dist/auth/authorization-parameters.d.ts.map +1 -0
  27. package/dist/auth/route-protection.server.d.ts +20 -4
  28. package/dist/auth/route-protection.server.d.ts.map +1 -1
  29. package/dist/auth/server.d.ts +1 -1
  30. package/dist/auth/server.d.ts.map +1 -1
  31. package/dist/auth/server.js +5 -5
  32. package/dist/auth/types.d.ts +24 -2
  33. package/dist/auth/types.d.ts.map +1 -1
  34. package/dist/{auth.server-B3ODGIX4.js → auth.server-D5oiz9aF.js} +62 -53
  35. package/dist/auth.server-D5oiz9aF.js.map +1 -0
  36. package/dist/{auth.server-wdKsjQsn.js → auth.server-lC94lmlx.js} +3 -3
  37. package/dist/identity/identity-context.server.d.ts +2 -0
  38. package/dist/identity/identity-context.server.d.ts.map +1 -1
  39. package/dist/identity/identity-store.d.ts +19 -2
  40. package/dist/identity/identity-store.d.ts.map +1 -1
  41. package/dist/identity/index.js +2 -2
  42. package/dist/identity/server.js +2 -2
  43. package/dist/identity/types.d.ts +3 -1
  44. package/dist/identity/types.d.ts.map +1 -1
  45. package/dist/{identity-yT2ijZF0.js → identity-C5un-xAs.js} +104 -60
  46. package/dist/identity-C5un-xAs.js.map +1 -0
  47. package/dist/index.js +8 -8
  48. package/dist/logging/index.js +1 -1
  49. package/dist/{logging-_h2mi3L9.js → logging-DviiAkLx.js} +2 -2
  50. package/dist/{logging-_h2mi3L9.js.map → logging-DviiAkLx.js.map} +1 -1
  51. package/dist/permissions/constants.d.ts +3 -0
  52. package/dist/permissions/constants.d.ts.map +1 -1
  53. package/dist/permissions/index.js +1 -1
  54. package/dist/permissions/permission-store.d.ts +1 -1
  55. package/dist/permissions/types.d.ts +1 -1
  56. package/dist/permissions/types.d.ts.map +1 -1
  57. package/dist/{permissions-OUK8Eql2.js → permissions-_n1hIG7Q.js} +6 -12
  58. package/dist/permissions-_n1hIG7Q.js.map +1 -0
  59. package/dist/query-client/types.d.ts +9 -9
  60. package/dist/query-client/types.d.ts.map +1 -1
  61. package/dist/query-client-Bh3TyB8W.js.map +1 -1
  62. package/dist/react-router/index.js +8 -8
  63. package/dist/react-router/server.js +14 -14
  64. package/dist/{redis-session-storage.server-D0-72FV-.js → redis-session-storage.server-v2VcpFsQ.js} +2 -2
  65. package/dist/{redis-session-storage.server-D0-72FV-.js.map → redis-session-storage.server-v2VcpFsQ.js.map} +1 -1
  66. package/dist/{server-B7JN86_0.js → server-B6PCxc-T.js} +31 -83
  67. package/dist/server-B6PCxc-T.js.map +1 -0
  68. package/dist/{server-DeBlxoaW.js → server-C96NMFBy.js} +17 -9
  69. package/dist/server-C96NMFBy.js.map +1 -0
  70. package/dist/{server-Ce9jQRdL.js → server-Ca-3DJf2.js} +44 -11
  71. package/dist/server-Ca-3DJf2.js.map +1 -0
  72. package/dist/{server-BmiuV28c.js → server-Dxsww9v9.js} +5 -4
  73. package/dist/server-Dxsww9v9.js.map +1 -0
  74. package/dist/server.js +14 -14
  75. package/dist/signalr/index.js +1 -1
  76. package/dist/signalr/types.d.ts +1 -1
  77. package/dist/{signalr-CSfCz1Ik.js → signalr-k-70VHKo.js} +3 -2
  78. package/dist/signalr-k-70VHKo.js.map +1 -0
  79. package/dist/tenant/index.js +2 -2
  80. package/dist/tenant/server.js +4 -4
  81. package/dist/tenant/tenant-context.d.ts +17 -1
  82. package/dist/tenant/tenant-context.d.ts.map +1 -1
  83. package/dist/tenant/tenant-cookie.server.d.ts.map +1 -1
  84. package/dist/tenant/tenant-store.d.ts +54 -9
  85. package/dist/tenant/tenant-store.d.ts.map +1 -1
  86. package/dist/tenant/tenant.server.d.ts +20 -1
  87. package/dist/tenant/tenant.server.d.ts.map +1 -1
  88. package/dist/tenant/types.d.ts +29 -9
  89. package/dist/tenant/types.d.ts.map +1 -1
  90. package/dist/tenant-DfLemb6n.js +384 -0
  91. package/dist/tenant-DfLemb6n.js.map +1 -0
  92. package/docs/adapters.md +87 -0
  93. package/docs/architecture.md +193 -0
  94. package/docs/backend-adaptation.md +249 -0
  95. package/docs/codex-for-oss-application.md +31 -0
  96. package/docs/codex-maintenance.md +47 -0
  97. package/docs/installation.md +213 -0
  98. package/docs/module-reference.md +207 -0
  99. package/docs/releasing.md +92 -0
  100. package/package.json +21 -3
  101. package/dist/access-DlAqsVGQ.js.map +0 -1
  102. package/dist/api-client-CZapXIF8.js.map +0 -1
  103. package/dist/auth.server-B3ODGIX4.js.map +0 -1
  104. package/dist/identity-yT2ijZF0.js.map +0 -1
  105. package/dist/permissions-OUK8Eql2.js.map +0 -1
  106. package/dist/server-B7JN86_0.js.map +0 -1
  107. package/dist/server-BmiuV28c.js.map +0 -1
  108. package/dist/server-Ce9jQRdL.js.map +0 -1
  109. package/dist/server-DeBlxoaW.js.map +0 -1
  110. package/dist/signalr-CSfCz1Ik.js.map +0 -1
  111. package/dist/tenant-BErqEENp.js +0 -256
  112. package/dist/tenant-BErqEENp.js.map +0 -1
@@ -1,8 +1,8 @@
1
- import { getAuthSession } from "./redis-session-storage.server-D0-72FV-.js";
1
+ import { getAuthSession } from "./redis-session-storage.server-v2VcpFsQ.js";
2
2
 
3
3
  //#region src/tenant/tenant-cookie.server.ts
4
4
  const DEFAULT_TENANT_COOKIE_CONFIG = {
5
- name: "__active-org",
5
+ name: "__spine_tenant",
6
6
  maxAge: 60 * 60 * 24 * 365,
7
7
  path: "/",
8
8
  secure: process.env.NODE_ENV === "production",
@@ -13,6 +13,14 @@ let tenantCookieConfig = { ...DEFAULT_TENANT_COOKIE_CONFIG };
13
13
  function getTenantCookieConfig() {
14
14
  return tenantCookieConfig;
15
15
  }
16
+ function readCookieValue(cookieHeader, name) {
17
+ for (const segment of cookieHeader.split(";")) {
18
+ const [rawName, ...rawValue] = segment.split("=");
19
+ if (rawName?.trim() !== name || rawValue.length === 0) continue;
20
+ return decodeURIComponent(rawValue.join("="));
21
+ }
22
+ return null;
23
+ }
16
24
  /**
17
25
  * Get active tenant from cookie
18
26
  */
@@ -20,9 +28,7 @@ async function getActiveTenant(request) {
20
28
  const config = getTenantCookieConfig();
21
29
  const cookies = request.headers.get("Cookie");
22
30
  if (!cookies) return null;
23
- const match = cookies.match(new RegExp(`${config.name}=([^;]+)`));
24
- if (!match) return null;
25
- return decodeURIComponent(match[1]);
31
+ return readCookieValue(cookies, config.name);
26
32
  }
27
33
  /**
28
34
  * Set active tenant cookie value
@@ -61,6 +67,11 @@ function resetTenantCookieConfig() {
61
67
  //#endregion
62
68
  //#region src/tenant/tenant.server.ts
63
69
  let identityContextFetcher = null;
70
+ let resolveInitialTenant = ({ identityContext }) => {
71
+ const membership = identityContext?.memberships?.[0];
72
+ return membership?.tenantId ?? membership?.id ?? null;
73
+ };
74
+ let resolveAvailableTenants = ({ identityContext }) => identityContext?.memberships?.map((membership) => membership.tenantId ?? membership.id).filter((tenantId) => Boolean(tenantId)) ?? [];
64
75
  /**
65
76
  * Configure identity context fetcher
66
77
  */
@@ -68,6 +79,22 @@ function configureIdentityContextFetcher(fetcher) {
68
79
  identityContextFetcher = fetcher;
69
80
  }
70
81
  /**
82
+ * Configure tenant resolution for custom backend identity contracts.
83
+ */
84
+ function configureTenantResolution(config) {
85
+ if (config.identityContextFetcher) identityContextFetcher = config.identityContextFetcher;
86
+ if (config.resolveInitialTenant) resolveInitialTenant = config.resolveInitialTenant;
87
+ if (config.resolveAvailableTenants) resolveAvailableTenants = config.resolveAvailableTenants;
88
+ }
89
+ function resetTenantResolutionConfig() {
90
+ identityContextFetcher = null;
91
+ resolveInitialTenant = ({ identityContext }) => {
92
+ const membership = identityContext?.memberships?.[0];
93
+ return membership?.tenantId ?? membership?.id ?? null;
94
+ };
95
+ resolveAvailableTenants = ({ identityContext }) => identityContext?.memberships?.map((membership) => membership.tenantId ?? membership.id).filter((tenantId) => Boolean(tenantId)) ?? [];
96
+ }
97
+ /**
71
98
  * Get current active tenant from cookie
72
99
  */
73
100
  async function getCurrentTenant(request) {
@@ -92,8 +119,11 @@ async function getTenantFromIdentityContext(request) {
92
119
  return null;
93
120
  }
94
121
  const context = await identityContextFetcher(request);
95
- if (context?.memberships && context.memberships.length > 0) return context.memberships[0].tenantId;
96
- return null;
122
+ return resolveInitialTenant({
123
+ request,
124
+ session: sessionData,
125
+ identityContext: context
126
+ });
97
127
  } catch (error) {
98
128
  console.error("Error getting tenant from identity context:", error);
99
129
  return null;
@@ -111,8 +141,11 @@ async function getAvailableTenants(request) {
111
141
  return [];
112
142
  }
113
143
  const context = await identityContextFetcher(request);
114
- if (context?.memberships && context.memberships.length > 0) return context.memberships.map((m) => m.tenantId);
115
- return [];
144
+ return resolveAvailableTenants({
145
+ request,
146
+ session: sessionData,
147
+ identityContext: context
148
+ });
116
149
  } catch (error) {
117
150
  console.error("Error getting available tenants:", error);
118
151
  return [];
@@ -181,5 +214,5 @@ async function clearCurrentTenant() {
181
214
  }
182
215
 
183
216
  //#endregion
184
- export { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, setActiveTenant, setCurrentTenant };
185
- //# sourceMappingURL=server-Ce9jQRdL.js.map
217
+ export { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, configureTenantResolution, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, resetTenantResolutionConfig, setActiveTenant, setCurrentTenant };
218
+ //# sourceMappingURL=server-Ca-3DJf2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-Ca-3DJf2.js","names":["DEFAULT_TENANT_COOKIE_CONFIG: Required<TenantCookieConfig>","tenantCookieConfig: Required<TenantCookieConfig>","cookieHeader: string","name: string","request: Request","tenantId: string","config: TenantCookieConfig","identityContextFetcher: IdentityContextFetcher | null","resolveInitialTenant: NonNullable<TenantResolutionConfig['resolveInitialTenant']>","resolveAvailableTenants: NonNullable<TenantResolutionConfig['resolveAvailableTenants']>","fetcher: IdentityContextFetcher","config: TenantResolutionConfig","request: Request","tenantId: string"],"sources":["../src/tenant/tenant-cookie.server.ts","../src/tenant/tenant.server.ts"],"sourcesContent":["/**\n * Tenant Cookie Server Module\n * \n * Cookie-based tenant storage.\n */\n\nexport type TenantCookieSameSite = 'Strict' | 'Lax' | 'None';\n\nexport interface TenantCookieConfig {\n name?: string;\n maxAge?: number;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: TenantCookieSameSite;\n}\n\nconst DEFAULT_TENANT_COOKIE_CONFIG: Required<TenantCookieConfig> = {\n name: '__spine_tenant',\n maxAge: 60 * 60 * 24 * 365,\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n httpOnly: false,\n sameSite: 'Lax',\n};\n\nlet tenantCookieConfig: Required<TenantCookieConfig> = {\n ...DEFAULT_TENANT_COOKIE_CONFIG,\n};\n\nfunction getTenantCookieConfig(): Required<TenantCookieConfig> {\n return tenantCookieConfig;\n}\n\nfunction readCookieValue(cookieHeader: string, name: string): string | null {\n for (const segment of cookieHeader.split(';')) {\n const [rawName, ...rawValue] = segment.split('=');\n if (rawName?.trim() !== name || rawValue.length === 0) {\n continue;\n }\n\n return decodeURIComponent(rawValue.join('='));\n }\n\n return null;\n}\n\n/**\n * Get active tenant from cookie\n */\nexport async function getActiveTenant(request: Request): Promise<string | null> {\n const config = getTenantCookieConfig();\n const cookies = request.headers.get('Cookie');\n if (!cookies) return null;\n\n return readCookieValue(cookies, config.name);\n}\n\n/**\n * Set active tenant cookie value\n */\nexport async function setActiveTenant(tenantId: string): Promise<string> {\n const config = getTenantCookieConfig();\n const secure = config.secure ? '; Secure' : '';\n const httpOnly = config.httpOnly ? '; HttpOnly' : '';\n return `${config.name}=${encodeURIComponent(tenantId)}; Path=${config.path}${httpOnly}; SameSite=${config.sameSite}; Max-Age=${config.maxAge}${secure}`;\n}\n\n/**\n * Clear active tenant cookie value\n */\nexport async function clearActiveTenant(): Promise<string> {\n const config = getTenantCookieConfig();\n const secure = config.secure ? '; Secure' : '';\n const httpOnly = config.httpOnly ? '; HttpOnly' : '';\n return `${config.name}=; Path=${config.path}${httpOnly}; SameSite=${config.sameSite}; Max-Age=0${secure}`;\n}\n\n/**\n * Configure tenant cookie name\n */\nexport function configureTenantCookie(config: TenantCookieConfig): void {\n tenantCookieConfig = {\n ...tenantCookieConfig,\n ...config,\n };\n}\n\n/**\n * Reset tenant cookie config back to defaults.\n */\nexport function resetTenantCookieConfig(): void {\n tenantCookieConfig = {\n ...DEFAULT_TENANT_COOKIE_CONFIG,\n };\n}\n","/**\n * Tenant Server Module\n * \n * Server-side tenant management.\n */\n\nimport { getAuthSession } from '../auth/redis-session-storage.server';\nimport { getActiveTenant, setActiveTenant, clearActiveTenant } from './tenant-cookie.server';\nimport type { SessionData } from '../auth/types';\n\n/**\n * Identity context fetcher type (to avoid circular dependency)\n */\nexport type IdentityContextFetcher = (request: Request) => Promise<{\n memberships?: Array<{ tenantId?: string; id?: string; [key: string]: unknown }>;\n [key: string]: unknown;\n} | null>;\n\nexport interface TenantResolutionContext {\n request: Request;\n session: SessionData;\n identityContext: Awaited<ReturnType<IdentityContextFetcher>>;\n}\n\nexport interface TenantResolutionConfig {\n identityContextFetcher?: IdentityContextFetcher;\n resolveInitialTenant?: (context: TenantResolutionContext) => Promise<string | null> | string | null;\n resolveAvailableTenants?: (context: TenantResolutionContext) => Promise<string[]> | string[];\n}\n\nlet identityContextFetcher: IdentityContextFetcher | null = null;\nlet resolveInitialTenant: NonNullable<TenantResolutionConfig['resolveInitialTenant']> =\n ({ identityContext }) => {\n const membership = identityContext?.memberships?.[0];\n return membership?.tenantId ?? membership?.id ?? null;\n };\nlet resolveAvailableTenants: NonNullable<TenantResolutionConfig['resolveAvailableTenants']> =\n ({ identityContext }) =>\n identityContext?.memberships\n ?.map((membership) => membership.tenantId ?? membership.id)\n .filter((tenantId): tenantId is string => Boolean(tenantId)) ?? [];\n\n/**\n * Configure identity context fetcher\n */\nexport function configureIdentityContextFetcher(fetcher: IdentityContextFetcher): void {\n identityContextFetcher = fetcher;\n}\n\n/**\n * Configure tenant resolution for custom backend identity contracts.\n */\nexport function configureTenantResolution(config: TenantResolutionConfig): void {\n if (config.identityContextFetcher) {\n identityContextFetcher = config.identityContextFetcher;\n }\n if (config.resolveInitialTenant) {\n resolveInitialTenant = config.resolveInitialTenant;\n }\n if (config.resolveAvailableTenants) {\n resolveAvailableTenants = config.resolveAvailableTenants;\n }\n}\n\nexport function resetTenantResolutionConfig(): void {\n identityContextFetcher = null;\n resolveInitialTenant = ({ identityContext }) => {\n const membership = identityContext?.memberships?.[0];\n return membership?.tenantId ?? membership?.id ?? null;\n };\n resolveAvailableTenants = ({ identityContext }) =>\n identityContext?.memberships\n ?.map((membership) => membership.tenantId ?? membership.id)\n .filter((tenantId): tenantId is string => Boolean(tenantId)) ?? [];\n}\n\n/**\n * Get current active tenant from cookie\n */\nexport async function getCurrentTenant(request: Request): Promise<string | null> {\n try {\n const tenantFromCookie = await getActiveTenant(request);\n if (tenantFromCookie) {\n return tenantFromCookie;\n }\n return null;\n } catch (error) {\n console.error('Error getting current tenant:', error);\n return null;\n }\n}\n\n/**\n * Get tenant from identity context\n */\nexport async function getTenantFromIdentityContext(request: Request): Promise<string | null> {\n try {\n const sessionData = await getAuthSession(request);\n if (!sessionData?.user?.sub) {\n return null;\n }\n\n if (!identityContextFetcher) {\n console.warn('Identity context fetcher not configured');\n return null;\n }\n\n const context = await identityContextFetcher(request);\n return resolveInitialTenant({ request, session: sessionData, identityContext: context });\n } catch (error) {\n console.error('Error getting tenant from identity context:', error);\n return null;\n }\n}\n\n/**\n * Get available tenants from identity context\n */\nexport async function getAvailableTenants(request: Request): Promise<string[]> {\n try {\n const sessionData = await getAuthSession(request);\n if (!sessionData?.user?.sub) {\n return [];\n }\n\n if (!identityContextFetcher) {\n console.warn('Identity context fetcher not configured');\n return [];\n }\n\n const context = await identityContextFetcher(request);\n return resolveAvailableTenants({ request, session: sessionData, identityContext: context });\n } catch (error) {\n console.error('Error getting available tenants:', error);\n return [];\n }\n}\n\n/**\n * Set current active tenant\n */\nexport async function setCurrentTenant(\n request: Request,\n tenantId: string\n): Promise<{ headers: Headers; success: boolean; error?: string }> {\n try {\n const sessionData = await getAuthSession(request);\n\n if (!sessionData.user) {\n return { headers: new Headers(), success: false, error: 'No active session' };\n }\n\n const cookieValue = await setActiveTenant(tenantId);\n const headers = new Headers();\n headers.append('Set-Cookie', cookieValue);\n\n return { headers, success: true };\n } catch (error) {\n console.error('Failed to set current tenant:', error);\n return {\n headers: new Headers(),\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n}\n\n/**\n * Initialize tenant on first login\n */\nexport async function initializeTenant(\n request: Request\n): Promise<{ headers: Headers; tenantId: string } | null> {\n try {\n const sessionData = await getAuthSession(request);\n if (!sessionData?.user) {\n return null;\n }\n\n // Check if tenant is already set in cookie\n const currentTenant = await getCurrentTenant(request);\n if (currentTenant) {\n return null;\n }\n\n // Get tenant from identity context\n const tenantId = await getTenantFromIdentityContext(request);\n\n if (tenantId) {\n const cookieValue = await setActiveTenant(tenantId);\n const headers = new Headers();\n headers.append('Set-Cookie', cookieValue);\n return { headers, tenantId };\n }\n\n return null;\n } catch (error) {\n console.error('Failed to initialize tenant:', error);\n return null;\n }\n}\n\n/**\n * Clear current tenant\n */\nexport async function clearCurrentTenant(): Promise<Headers> {\n const cookieValue = await clearActiveTenant();\n const headers = new Headers();\n headers.append('Set-Cookie', cookieValue);\n return headers;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { logger } from "./logging-_h2mi3L9.js";
1
+ import { logger } from "./logging-DviiAkLx.js";
2
2
  import { isApiClientError } from "./types-BaaE6wjY.js";
3
3
 
4
4
  //#region src/identity/identity-context.server.ts
@@ -21,7 +21,7 @@ async function fetchIdentityContext(request) {
21
21
  const context = await identityAPIFetcher(request);
22
22
  logger.debug("Identity context fetched", {
23
23
  hasAnyMembership: context.hasAnyMembership,
24
- hasSubscription: context.hasSubscription,
24
+ hasEntitlement: context.hasEntitlement ?? context.hasSubscription,
25
25
  isOnboarded: context.isOnboarded,
26
26
  membershipCount: context.memberships?.length || 0
27
27
  });
@@ -107,7 +107,8 @@ async function contextToUserInfo(context, options = {}) {
107
107
  currentTenant: resolvedCurrentTenant,
108
108
  isOnboarded: context.isOnboarded ?? false,
109
109
  permissions,
110
- hasSubscription: context.hasSubscription ?? false,
110
+ hasEntitlement: context.hasEntitlement ?? context.hasSubscription ?? false,
111
+ hasSubscription: context.hasSubscription ?? context.hasEntitlement ?? false,
111
112
  userId: context.userId,
112
113
  email: context.email,
113
114
  firstName: context.firstName,
@@ -143,4 +144,4 @@ function updateContextVersion(userId, newVersion) {
143
144
 
144
145
  //#endregion
145
146
  export { clearIdentityContextCache, configureIdentityAPIFetcher, configurePermissionFetcher, contextToUserInfo, fetchIdentityContext, fetchUserPermissions, getIdentityContext, hasContextVersionChanged, updateContextVersion };
146
- //# sourceMappingURL=server-BmiuV28c.js.map
147
+ //# sourceMappingURL=server-Dxsww9v9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-Dxsww9v9.js","names":["identityAPIFetcher: IdentityAPIFetcher | null","fetcher: IdentityAPIFetcher","request: Request","error: unknown","userId: string","userId?: string","permissionFetcher: PermissionFetcher | null","fetcher: PermissionFetcher","tenantId: string","context: IdentityContextData","options: ContextToUserInfoOptions","permissions: string[]","newVersion: number"],"sources":["../src/identity/identity-context.server.ts"],"sourcesContent":["/**\n * Identity Context Server Module\n * \n * Server-side identity context management.\n */\n\nimport type { AddressData, IdentityContextData, TenantMembership } from './types';\nimport { isApiClientError } from '../api-client/types';\nimport { logger } from '../logging';\n\n/**\n * Identity API fetcher type (to avoid coupling with specific API client)\n */\nexport type IdentityAPIFetcher = (request: Request) => Promise<IdentityContextData>;\n\nlet identityAPIFetcher: IdentityAPIFetcher | null = null;\n\n/**\n * Configure identity API fetcher\n */\nexport function configureIdentityAPIFetcher(fetcher: IdentityAPIFetcher): void {\n identityAPIFetcher = fetcher;\n}\n\n// In-memory cache for identity context\nconst contextCache = new Map<\n string,\n {\n context: IdentityContextData;\n timestamp: number;\n version: number;\n }\n>();\n\nconst CONTEXT_CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Fetch identity context from backend\n */\nexport async function fetchIdentityContext(request: Request): Promise<IdentityContextData> {\n if (!identityAPIFetcher) {\n throw new Error('Identity API fetcher not configured. Call configureIdentityAPIFetcher first.');\n }\n\n try {\n logger.info('Fetching identity context');\n const context = await identityAPIFetcher(request);\n \n logger.debug('Identity context fetched', {\n hasAnyMembership: context.hasAnyMembership,\n hasEntitlement: context.hasEntitlement ?? context.hasSubscription,\n isOnboarded: context.isOnboarded,\n membershipCount: context.memberships?.length || 0,\n });\n\n return context;\n } catch (error: unknown) {\n logger.error('Failed to fetch identity context', error instanceof Error ? error : undefined);\n\n // Check if this is a CurrentUserMissing error\n if (isApiClientError(error) && error.response?.status === 404 && error.problemDetails?.title === 'CurrentUserMissing') {\n logger.error('CurrentUserMissing error detected - session is invalid');\n const invalidSessionError = new Error('INVALID_SESSION');\n (invalidSessionError as Error & { isInvalidSession: boolean }).isInvalidSession = true;\n throw invalidSessionError;\n }\n\n throw error;\n }\n}\n\n/**\n * Get cached identity context or fetch fresh if needed\n */\nexport async function getIdentityContext(\n request: Request,\n userId: string,\n forceRefresh = false\n): Promise<IdentityContextData> {\n const cacheKey = userId;\n const cached = contextCache.get(cacheKey);\n const now = Date.now();\n\n // Return cached if valid and not forcing refresh\n if (!forceRefresh && cached && now - cached.timestamp < CONTEXT_CACHE_TTL) {\n logger.debug('Using cached identity context for user', { userId });\n return cached.context;\n }\n\n // Fetch fresh context\n const context = await fetchIdentityContext(request);\n\n // Cache the result\n contextCache.set(cacheKey, {\n context,\n timestamp: now,\n version: context.contextVersion ?? 0,\n });\n\n logger.debug('Cached fresh identity context for user', { userId });\n return context;\n}\n\n/**\n * Clear identity context cache for user\n */\nexport function clearIdentityContextCache(userId?: string): void {\n if (userId) {\n contextCache.delete(userId);\n logger.debug('Cleared identity context cache for user', { userId });\n } else {\n contextCache.clear();\n logger.debug('Cleared all identity context cache');\n }\n}\n\n/**\n * Permission fetcher type\n */\nexport type PermissionFetcher = (request: Request, tenantId: string) => Promise<string[]>;\n\nlet permissionFetcher: PermissionFetcher | null = null;\n\n/**\n * Configure permission fetcher\n */\nexport function configurePermissionFetcher(fetcher: PermissionFetcher): void {\n permissionFetcher = fetcher;\n}\n\n/**\n * Fetch user permissions for a specific tenant\n */\nexport async function fetchUserPermissions(request: Request, tenantId: string): Promise<string[]> {\n if (!tenantId) {\n logger.warn('No tenant ID provided, skipping permission fetch');\n return [];\n }\n\n if (!permissionFetcher) {\n throw new Error('Permission fetcher not configured. Call configurePermissionFetcher first.');\n }\n\n try {\n return await permissionFetcher(request, tenantId);\n } catch (error) {\n logger.error('Failed to fetch user permissions', error instanceof Error ? error : undefined);\n return [];\n }\n}\n\nexport interface UserContextInfo {\n tenants: string[];\n memberships: TenantMembership[];\n currentTenant?: string;\n isOnboarded: boolean;\n permissions: string[];\n hasEntitlement: boolean;\n /** @deprecated Use hasEntitlement or app-specific fields instead. */\n hasSubscription: boolean;\n userId?: string;\n email?: string;\n firstName?: string | null;\n lastName?: string | null;\n displayName?: string | null;\n profileImageUrl?: string | null;\n phoneNumber?: string | null;\n timeZone?: string;\n addresses?: AddressData[];\n hasOwnerMembership: boolean;\n}\n\nexport interface ContextToUserInfoOptions {\n currentTenant?: string | null;\n request?: Request;\n}\n\n/**\n * Convert raw identity context into a tenant-aware user info shape.\n */\nexport async function contextToUserInfo(\n context: IdentityContextData,\n options: ContextToUserInfoOptions = {}\n): Promise<UserContextInfo> {\n const memberships = context.memberships || [];\n const tenants = memberships.map((membership) => membership.tenantId);\n const resolvedCurrentTenant =\n options.currentTenant && tenants.includes(options.currentTenant)\n ? options.currentTenant\n : tenants[0] || undefined;\n\n let permissions: string[] = [];\n if (resolvedCurrentTenant && options.request) {\n permissions = await fetchUserPermissions(options.request, resolvedCurrentTenant);\n }\n\n return {\n tenants,\n memberships,\n currentTenant: resolvedCurrentTenant,\n isOnboarded: context.isOnboarded ?? false,\n permissions,\n hasEntitlement: context.hasEntitlement ?? context.hasSubscription ?? false,\n hasSubscription: context.hasSubscription ?? context.hasEntitlement ?? false,\n userId: context.userId,\n email: context.email,\n firstName: context.firstName,\n lastName: context.lastName,\n displayName: context.displayName,\n profileImageUrl: context.profileImageUrl,\n phoneNumber: context.phoneNumber,\n timeZone: context.timeZone,\n addresses: context.addresses,\n hasOwnerMembership: context.hasOwnerMembership ?? false,\n };\n}\n\n/**\n * Check if a cached context version differs from the latest version.\n */\nexport function hasContextVersionChanged(userId: string, newVersion: number): boolean {\n const cached = contextCache.get(userId);\n return !cached || cached.version !== newVersion;\n}\n\n/**\n * Mark a cached identity context as stale after a version change.\n */\nexport function updateContextVersion(userId: string, newVersion: number): void {\n const cached = contextCache.get(userId);\n if (!cached) return;\n\n cached.version = newVersion;\n cached.timestamp = 0;\n logger.debug('Marked identity context as stale for user', {\n userId,\n version: newVersion,\n });\n}\n"],"mappings":";;;;AAeA,IAAIA,qBAAgD;;;;AAKpD,SAAgB,4BAA4BC,SAAmC;AAC7E,sBAAqB;AACtB;AAGD,MAAM,eAAe,IAAI;AASzB,MAAM,oBAAoB,IAAI,KAAK;;;;AAKnC,eAAsB,qBAAqBC,SAAgD;AACzF,MAAK,mBACH,OAAM,IAAI,MAAM;AAGlB,KAAI;AACF,SAAO,KAAK,4BAA4B;EACxC,MAAM,UAAU,MAAM,mBAAmB,QAAQ;AAEjD,SAAO,MAAM,4BAA4B;GACvC,kBAAkB,QAAQ;GAC1B,gBAAgB,QAAQ,kBAAkB,QAAQ;GAClD,aAAa,QAAQ;GACrB,iBAAiB,QAAQ,aAAa,UAAU;EACjD,EAAC;AAEF,SAAO;CACR,SAAQC,OAAgB;AACvB,SAAO,MAAM,oCAAoC,iBAAiB,QAAQ,eAAkB;AAG5F,MAAI,iBAAiB,MAAM,IAAI,MAAM,UAAU,WAAW,OAAO,MAAM,gBAAgB,UAAU,sBAAsB;AACrH,UAAO,MAAM,yDAAyD;GACtE,MAAM,sBAAsB,IAAI,MAAM;AACtC,GAAC,oBAA8D,mBAAmB;AAClF,SAAM;EACP;AAED,QAAM;CACP;AACF;;;;AAKD,eAAsB,mBACpBD,SACAE,QACA,eAAe,OACe;CAC9B,MAAM,WAAW;CACjB,MAAM,SAAS,aAAa,IAAI,SAAS;CACzC,MAAM,MAAM,KAAK,KAAK;AAGtB,MAAK,gBAAgB,UAAU,MAAM,OAAO,YAAY,mBAAmB;AACzE,SAAO,MAAM,0CAA0C,EAAE,OAAQ,EAAC;AAClE,SAAO,OAAO;CACf;CAGD,MAAM,UAAU,MAAM,qBAAqB,QAAQ;AAGnD,cAAa,IAAI,UAAU;EACzB;EACA,WAAW;EACX,SAAS,QAAQ,kBAAkB;CACpC,EAAC;AAEF,QAAO,MAAM,0CAA0C,EAAE,OAAQ,EAAC;AAClE,QAAO;AACR;;;;AAKD,SAAgB,0BAA0BC,QAAuB;AAC/D,KAAI,QAAQ;AACV,eAAa,OAAO,OAAO;AAC3B,SAAO,MAAM,2CAA2C,EAAE,OAAQ,EAAC;CACpE,OAAM;AACL,eAAa,OAAO;AACpB,SAAO,MAAM,qCAAqC;CACnD;AACF;AAOD,IAAIC,oBAA8C;;;;AAKlD,SAAgB,2BAA2BC,SAAkC;AAC3E,qBAAoB;AACrB;;;;AAKD,eAAsB,qBAAqBL,SAAkBM,UAAqC;AAChG,MAAK,UAAU;AACb,SAAO,KAAK,mDAAmD;AAC/D,SAAO,CAAE;CACV;AAED,MAAK,kBACH,OAAM,IAAI,MAAM;AAGlB,KAAI;AACF,SAAO,MAAM,kBAAkB,SAAS,SAAS;CAClD,SAAQ,OAAO;AACd,SAAO,MAAM,oCAAoC,iBAAiB,QAAQ,eAAkB;AAC5F,SAAO,CAAE;CACV;AACF;;;;AA+BD,eAAsB,kBACpBC,SACAC,UAAoC,CAAE,GACZ;CAC1B,MAAM,cAAc,QAAQ,eAAe,CAAE;CAC7C,MAAM,UAAU,YAAY,IAAI,CAAC,eAAe,WAAW,SAAS;CACpE,MAAM,wBACJ,QAAQ,iBAAiB,QAAQ,SAAS,QAAQ,cAAc,GAC5D,QAAQ,gBACR,QAAQ;CAEd,IAAIC,cAAwB,CAAE;AAC9B,KAAI,yBAAyB,QAAQ,QACnC,eAAc,MAAM,qBAAqB,QAAQ,SAAS,sBAAsB;AAGlF,QAAO;EACL;EACA;EACA,eAAe;EACf,aAAa,QAAQ,eAAe;EACpC;EACA,gBAAgB,QAAQ,kBAAkB,QAAQ,mBAAmB;EACrE,iBAAiB,QAAQ,mBAAmB,QAAQ,kBAAkB;EACtE,QAAQ,QAAQ;EAChB,OAAO,QAAQ;EACf,WAAW,QAAQ;EACnB,UAAU,QAAQ;EAClB,aAAa,QAAQ;EACrB,iBAAiB,QAAQ;EACzB,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,WAAW,QAAQ;EACnB,oBAAoB,QAAQ,sBAAsB;CACnD;AACF;;;;AAKD,SAAgB,yBAAyBP,QAAgBQ,YAA6B;CACpF,MAAM,SAAS,aAAa,IAAI,OAAO;AACvC,SAAQ,UAAU,OAAO,YAAY;AACtC;;;;AAKD,SAAgB,qBAAqBR,QAAgBQ,YAA0B;CAC7E,MAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAK,OAAQ;AAEb,QAAO,UAAU;AACjB,QAAO,YAAY;AACnB,QAAO,MAAM,6CAA6C;EACxD;EACA,SAAS;CACV,EAAC;AACH"}
package/dist/server.js CHANGED
@@ -1,20 +1,20 @@
1
- import { LOG_LEVEL_PRIORITY, LogLevel, Logger, createLogger, defaultLoggerConfig, logger } from "./logging-_h2mi3L9.js";
1
+ import { LOG_LEVEL_PRIORITY, LogLevel, Logger, createLogger, defaultLoggerConfig, logger } from "./logging-DviiAkLx.js";
2
2
  import { PermissionChecker } from "./permission-service-CvGpwI0d.js";
3
- import { PERMISSION_MODULES, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, getPermissionChecker, getPermissions, initializePermissions, useAllPermissions, useHasModulePermission, useHasPermission, useHasPermissions, useModulePermission, usePermission, usePermissionChecker, usePermissionStore, usePermissions } from "./permissions-OUK8Eql2.js";
4
- import { evaluateAccessRequirement } from "./access-DlAqsVGQ.js";
5
- import { TenantProvider, configureTenantEndpoints, initializeTenantStore, useCurrentOrganization, useCurrentTenant, useOrganization, useTenant, useTenantStore, useTenantSwitcher } from "./tenant-BErqEENp.js";
6
- import { IdentityContextProvider, configureIdentityEndpoints, configureIdentityStore, resetIdentityStoreConfig, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useUserPermissions, useUserTenants } from "./identity-yT2ijZF0.js";
3
+ import { PERMISSION_MODULES, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, getPermissionChecker, getPermissions, initializePermissions, useAllPermissions, useHasModulePermission, useHasPermission, useHasPermissions, useModulePermission, usePermission, usePermissionChecker, usePermissionStore, usePermissions } from "./permissions-_n1hIG7Q.js";
4
+ import { evaluateAccessRequirement } from "./access-CGrsDMwu.js";
5
+ import { TenantProvider, configureTenantClient, configureTenantEndpoints, getTenantCookieName, initializeTenantStore, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetTenantClientConfig, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useOrganization, useTenant, useTenantData, useTenantStore, useTenantSwitcher } from "./tenant-DfLemb6n.js";
6
+ import { IdentityContextProvider, configureIdentityEndpoints, configureIdentityStore, initialIdentityContext, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, resetIdentityStoreConfig, useHasEntitlement, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useUserPermissions, useUserTenants } from "./identity-C5un-xAs.js";
7
7
  import { isApiClientError } from "./types-BaaE6wjY.js";
8
- import { ApiError, ErrorCodes, ErrorHandler, calculateBackoffDelay, createRetryFetch, fetchWithTimeout, handleApiError, isRetryableError, withRetry } from "./api-client-CZapXIF8.js";
9
- import { IdentitySignalRClient, SignalRClient, cleanupSignalR, createIdentitySignalRClient, getIdentitySignalRClient, initializeSignalR } from "./signalr-CSfCz1Ik.js";
8
+ import { ApiError, ErrorCodes, ErrorHandler, calculateBackoffDelay, createRetryFetch, fetchWithTimeout, handleApiError, isRetryableError, withRetry } from "./api-client-CgZUMukO.js";
9
+ import { IdentitySignalRClient, SignalRClient, cleanupSignalR, createIdentitySignalRClient, getIdentitySignalRClient, initializeSignalR } from "./signalr-k-70VHKo.js";
10
10
  import { cachePresets, createQueryClient, createQueryKeyFactory, invalidationHelpers } from "./query-client-Bh3TyB8W.js";
11
11
  import "./src-B9rDUgSb.js";
12
- import { AUTH_ERROR_COOKIE_PREFIX, cleanupExpiredOAuthStates, closeRedisConnection, createAuthSession, createOAuthState, deleteOAuthState, destroyAuthSession, destroyAuthSessionById, destroyAuthSessionsByIdentitySession, destroyAuthSessionsBySessionState, destroyAuthSessionsBySid, destroyAuthSessionsForUser, getAuthSession, getAuthSessionById, getCurrentAuthSessionId, getOAuthState, isSessionValid, listAuthSessionDataForUser, listAuthSessionsForUser, listCurrentUserAuthSessions, requireAuthSession, updateAuthSession } from "./redis-session-storage.server-D0-72FV-.js";
13
- import { clearAuthErrorHeaders, clearAuthServerCache, configureAuthClaimMapping, extractUserInfo, getAccessToken, getAuthError, getUser, handleBackChannelLogout, handleCallback, handleFrontChannelLogout, hasAuthError, login, logout, refreshTokens, requireAuth, resetAuthClaimMapping } from "./auth.server-B3ODGIX4.js";
14
- import { attemptTokenRefresh, authRoute, configureRouteProtection, isTokenExpiredResponse, onboardingRoute, protectRoute, publicRoute, resetRouteProtectionConfig, shouldAttemptTokenRefresh, shouldRefreshToken, subscriptionRoute } from "./server-B7JN86_0.js";
15
- import { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, setActiveTenant, setCurrentTenant } from "./server-Ce9jQRdL.js";
16
- import { clearIdentityContextCache, configureIdentityAPIFetcher, configurePermissionFetcher, contextToUserInfo, fetchIdentityContext, fetchUserPermissions, getIdentityContext, hasContextVersionChanged, updateContextVersion } from "./server-BmiuV28c.js";
12
+ import { AUTH_ERROR_COOKIE_PREFIX, cleanupExpiredOAuthStates, closeRedisConnection, createAuthSession, createOAuthState, deleteOAuthState, destroyAuthSession, destroyAuthSessionById, destroyAuthSessionsByIdentitySession, destroyAuthSessionsBySessionState, destroyAuthSessionsBySid, destroyAuthSessionsForUser, getAuthSession, getAuthSessionById, getCurrentAuthSessionId, getOAuthState, isSessionValid, listAuthSessionDataForUser, listAuthSessionsForUser, listCurrentUserAuthSessions, requireAuthSession, updateAuthSession } from "./redis-session-storage.server-v2VcpFsQ.js";
13
+ import { clearAuthErrorHeaders, clearAuthServerCache, configureAuthClaimMapping, extractUserInfo, getAccessToken, getAuthError, getUser, handleBackChannelLogout, handleCallback, handleFrontChannelLogout, hasAuthError, login, logout, refreshTokens, requireAuth, resetAuthClaimMapping } from "./auth.server-D5oiz9aF.js";
14
+ import { attemptTokenRefresh, authRoute, configureRouteProtection, isTokenExpiredResponse, onboardingRoute, policyRoute, protectRoute, protectedRoute, publicRoute, resetRouteProtectionConfig, shouldAttemptTokenRefresh, shouldRefreshToken, subscriptionRoute } from "./server-B6PCxc-T.js";
15
+ import { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, configureTenantResolution, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, resetTenantResolutionConfig, setActiveTenant, setCurrentTenant } from "./server-Ca-3DJf2.js";
16
+ import { clearIdentityContextCache, configureIdentityAPIFetcher, configurePermissionFetcher, contextToUserInfo, fetchIdentityContext, fetchUserPermissions, getIdentityContext, hasContextVersionChanged, updateContextVersion } from "./server-Dxsww9v9.js";
17
17
  import { checkPermission, configurePermissionRouteProtection, requirePermission, resetPermissionRouteProtection, withPermission } from "./server-hGrElJMG.js";
18
- import { createAPIConfigFactory, createApiClient, createFetchMiddleware } from "./server-DeBlxoaW.js";
18
+ import { createAPIConfigFactory, createApiClient, createFetchMiddleware } from "./server-C96NMFBy.js";
19
19
 
20
- export { AUTH_ERROR_COOKIE_PREFIX, ApiError, ErrorCodes, ErrorHandler, IdentityContextProvider, IdentitySignalRClient, LOG_LEVEL_PRIORITY, LogLevel, Logger, PERMISSION_MODULES, PermissionChecker, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, SignalRClient, TenantProvider, attemptTokenRefresh, authRoute, cachePresets, calculateBackoffDelay, checkPermission, cleanupExpiredOAuthStates, cleanupSignalR, clearActiveTenant, clearAuthErrorHeaders, clearAuthServerCache, clearCurrentTenant, clearIdentityContextCache, closeRedisConnection, configureAuthClaimMapping, configureIdentityAPIFetcher, configureIdentityContextFetcher, configureIdentityEndpoints, configureIdentityStore, configurePermissionFetcher, configurePermissionRouteProtection, configureRouteProtection, configureTenantCookie, configureTenantEndpoints, contextToUserInfo, createAPIConfigFactory, createApiClient, createAuthSession, createFetchMiddleware, createIdentitySignalRClient, createLogger, createOAuthState, createQueryClient, createQueryKeyFactory, createRetryFetch, defaultLoggerConfig, deleteOAuthState, destroyAuthSession, destroyAuthSessionById, destroyAuthSessionsByIdentitySession, destroyAuthSessionsBySessionState, destroyAuthSessionsBySid, destroyAuthSessionsForUser, evaluateAccessRequirement, extractUserInfo, fetchIdentityContext, fetchUserPermissions, fetchWithTimeout, getAccessToken, getActiveTenant, getAuthError, getAuthSession, getAuthSessionById, getAvailableTenants, getCurrentAuthSessionId, getCurrentTenant, getIdentityContext, getIdentitySignalRClient, getOAuthState, getPermissionChecker, getPermissions, getTenantFromIdentityContext, getUser, handleApiError, handleBackChannelLogout, handleCallback, handleFrontChannelLogout, hasAuthError, hasContextVersionChanged, initializePermissions, initializeSignalR, initializeTenant, initializeTenantStore, invalidationHelpers, isApiClientError, isRetryableError, isSessionValid, isTokenExpiredResponse, listAuthSessionDataForUser, listAuthSessionsForUser, listCurrentUserAuthSessions, logger, login, logout, onboardingRoute, protectRoute, publicRoute, refreshTokens, requireAuth, requireAuthSession, requirePermission, resetAuthClaimMapping, resetIdentityStoreConfig, resetPermissionRouteProtection, resetRouteProtectionConfig, resetTenantCookieConfig, setActiveTenant, setCurrentTenant, shouldAttemptTokenRefresh, shouldRefreshToken, subscriptionRoute, updateAuthSession, updateContextVersion, useAllPermissions, useCurrentOrganization, useCurrentTenant, useHasModulePermission, useHasPermission, useHasPermissions, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useModulePermission, useOrganization, usePermission, usePermissionChecker, usePermissionStore, usePermissions, useTenant, useTenantStore, useTenantSwitcher, useUserPermissions, useUserTenants, withPermission, withRetry };
20
+ export { AUTH_ERROR_COOKIE_PREFIX, ApiError, ErrorCodes, ErrorHandler, IdentityContextProvider, IdentitySignalRClient, LOG_LEVEL_PRIORITY, LogLevel, Logger, PERMISSION_MODULES, PermissionChecker, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, SignalRClient, TenantProvider, attemptTokenRefresh, authRoute, cachePresets, calculateBackoffDelay, checkPermission, cleanupExpiredOAuthStates, cleanupSignalR, clearActiveTenant, clearAuthErrorHeaders, clearAuthServerCache, clearCurrentTenant, clearIdentityContextCache, closeRedisConnection, configureAuthClaimMapping, configureIdentityAPIFetcher, configureIdentityContextFetcher, configureIdentityEndpoints, configureIdentityStore, configurePermissionFetcher, configurePermissionRouteProtection, configureRouteProtection, configureTenantClient, configureTenantCookie, configureTenantEndpoints, configureTenantResolution, contextToUserInfo, createAPIConfigFactory, createApiClient, createAuthSession, createFetchMiddleware, createIdentitySignalRClient, createLogger, createOAuthState, createQueryClient, createQueryKeyFactory, createRetryFetch, defaultLoggerConfig, deleteOAuthState, destroyAuthSession, destroyAuthSessionById, destroyAuthSessionsByIdentitySession, destroyAuthSessionsBySessionState, destroyAuthSessionsBySid, destroyAuthSessionsForUser, evaluateAccessRequirement, extractUserInfo, fetchIdentityContext, fetchUserPermissions, fetchWithTimeout, getAccessToken, getActiveTenant, getAuthError, getAuthSession, getAuthSessionById, getAvailableTenants, getCurrentAuthSessionId, getCurrentTenant, getIdentityContext, getIdentitySignalRClient, getOAuthState, getPermissionChecker, getPermissions, getTenantCookieName, getTenantFromIdentityContext, getUser, handleApiError, handleBackChannelLogout, handleCallback, handleFrontChannelLogout, hasAuthError, hasContextVersionChanged, initialIdentityContext, initializePermissions, initializeSignalR, initializeTenant, initializeTenantStore, invalidationHelpers, isApiClientError, isRetryableError, isSessionValid, isTokenExpiredResponse, listAuthSessionDataForUser, listAuthSessionsForUser, listCurrentUserAuthSessions, logger, login, logout, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, normalizeTenantDataPayload, normalizeTenantSwitchPayload, onboardingRoute, policyRoute, protectRoute, protectedRoute, publicRoute, refreshTokens, requireAuth, requireAuthSession, requirePermission, resetAuthClaimMapping, resetIdentityStoreConfig, resetPermissionRouteProtection, resetRouteProtectionConfig, resetTenantClientConfig, resetTenantCookieConfig, resetTenantResolutionConfig, setActiveTenant, setCurrentTenant, shouldAttemptTokenRefresh, shouldRefreshToken, subscriptionRoute, updateAuthSession, updateContextVersion, useAllPermissions, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useHasEntitlement, useHasModulePermission, useHasPermission, useHasPermissions, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useModulePermission, useOrganization, usePermission, usePermissionChecker, usePermissionStore, usePermissions, useTenant, useTenantData, useTenantStore, useTenantSwitcher, useUserPermissions, useUserTenants, withPermission, withRetry };
@@ -1,3 +1,3 @@
1
- import { IdentitySignalRClient, SignalRClient, cleanupSignalR, createIdentitySignalRClient, getIdentitySignalRClient, initializeSignalR } from "../signalr-CSfCz1Ik.js";
1
+ import { IdentitySignalRClient, SignalRClient, cleanupSignalR, createIdentitySignalRClient, getIdentitySignalRClient, initializeSignalR } from "../signalr-k-70VHKo.js";
2
2
 
3
3
  export { IdentitySignalRClient, SignalRClient, cleanupSignalR, createIdentitySignalRClient, getIdentitySignalRClient, initializeSignalR };
@@ -15,7 +15,7 @@ export type SignalRConnectionState = 'Connecting' | 'Connected' | 'Reconnecting'
15
15
  */
16
16
  export interface SignalRClientConfig {
17
17
  /**
18
- * Base URL for SignalR hub (defaults to API base URL)
18
+ * Base URL for SignalR hub. Defaults to window.location.origin in browsers.
19
19
  */
20
20
  baseUrl?: string;
21
21
  /**
@@ -87,7 +87,8 @@ var SignalRClient = class {
87
87
  */
88
88
  buildHubUrl() {
89
89
  let baseUrl = this.config.baseUrl;
90
- if (!baseUrl && typeof window !== "undefined") baseUrl = window.location.hostname === "localhost" ? "https://localhost:5001" : window.location.origin;
90
+ if (!baseUrl && typeof window !== "undefined") baseUrl = window.location.origin;
91
+ if (!baseUrl) throw new Error("SignalR baseUrl is required outside browser runtimes");
91
92
  return `${baseUrl}${this.config.hubPath}`;
92
93
  }
93
94
  /**
@@ -271,4 +272,4 @@ async function cleanupSignalR() {
271
272
 
272
273
  //#endregion
273
274
  export { IdentitySignalRClient, SignalRClient, cleanupSignalR, createIdentitySignalRClient, getIdentitySignalRClient, initializeSignalR };
274
- //# sourceMappingURL=signalr-CSfCz1Ik.js.map
275
+ //# sourceMappingURL=signalr-k-70VHKo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signalr-k-70VHKo.js","names":["DEFAULT_CONFIG: Required<Omit<SignalRClientConfig, 'hubPath' | 'baseUrl'>>","config: SignalRClientConfig","accessToken: string | null","event: unknown","eventName: string","handler: SignalREventHandler<T>","methodName: string","message: string","level: 'info' | 'warn' | 'error'","options: Omit<SignalRClientConfig, 'hubPath'>","handler: IdentityContextChangeHandler","identityClientInstance: IdentitySignalRClient | null"],"sources":["../src/signalr/signalr-client.ts"],"sourcesContent":["/**\n * SignalR Client for Real-time Updates\n * \n * This client connects to SignalR hub and listens for real-time events.\n * Supports identity context changes, permissions updates, etc.\n */\n\nimport { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';\nimport type {\n SignalRClientConfig,\n SignalRConnectionState,\n SignalREventHandler,\n IdentityContextChangedEvent,\n IdentityContextChangeHandler,\n} from './types';\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<SignalRClientConfig, 'hubPath' | 'baseUrl'>> = {\n maxReconnectAttempts: 5,\n reconnectDelay: 1000,\n verbose: false,\n autoReconnectOnVisibility: true,\n};\n\n/**\n * SignalR Client Class\n * \n * Generic SignalR client that can be used for any hub connection.\n */\nexport class SignalRClient {\n private connection: HubConnection | null = null;\n private accessToken: string | null = null;\n private isConnecting = false;\n private reconnectAttempts = 0;\n private config: Required<Omit<SignalRClientConfig, 'baseUrl'>> & { baseUrl?: string };\n private eventHandlers: Map<string, Set<SignalREventHandler>> = new Map();\n private visibilityHandler: (() => void) | null = null;\n\n constructor(config: SignalRClientConfig) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config,\n };\n\n // Auto-reconnect on page visibility change\n if (typeof document !== 'undefined' && this.config.autoReconnectOnVisibility) {\n this.visibilityHandler = () => {\n if (document.visibilityState === 'visible' && this.connection?.state === 'Disconnected') {\n this.log('🔄 Page became visible, attempting reconnection...');\n this.connect(this.accessToken);\n }\n };\n document.addEventListener('visibilitychange', this.visibilityHandler);\n }\n }\n\n /**\n * Connect to SignalR hub\n */\n async connect(accessToken: string | null): Promise<void> {\n if (!accessToken) {\n this.log('⚠️ No access token provided for SignalR connection', 'warn');\n return;\n }\n\n if (this.isConnecting) {\n this.log('🔄 Connection already in progress...');\n return;\n }\n\n if (this.connection?.state === 'Connected') {\n this.log('✅ Already connected');\n return;\n }\n\n this.accessToken = accessToken;\n this.isConnecting = true;\n\n try {\n const hubUrl = this.buildHubUrl();\n\n this.connection = new HubConnectionBuilder()\n .withUrl(hubUrl, {\n accessTokenFactory: () => accessToken,\n })\n .withAutomaticReconnect({\n nextRetryDelayInMilliseconds: (retryContext) => {\n // Exponential backoff: 1s, 2s, 4s, 8s, 16s\n const delay = Math.min(\n this.config.reconnectDelay * Math.pow(2, retryContext.previousRetryCount),\n 16000\n );\n this.log(`🔄 Reconnect attempt ${retryContext.previousRetryCount + 1} in ${delay}ms`);\n return delay;\n },\n })\n .configureLogging(this.config.verbose ? LogLevel.Information : LogLevel.Warning)\n .build();\n\n // Setup event handlers\n this.setupConnectionHandlers();\n\n // Connect\n this.log(`🔄 Connecting to SignalR hub: ${hubUrl}`);\n await this.connection.start();\n\n this.log(`✅ Connected successfully (ID: ${this.connection.connectionId})`);\n this.reconnectAttempts = 0;\n } catch (error) {\n this.log(`❌ Connection failed: ${error}`, 'error');\n this.reconnectAttempts++;\n\n // Retry with exponential backoff\n if (this.reconnectAttempts <= this.config.maxReconnectAttempts) {\n const delay = Math.min(\n this.config.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1),\n 30000\n );\n this.log(\n `🔄 Retrying in ${delay}ms (attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`\n );\n\n setTimeout(() => {\n this.connect(accessToken);\n }, delay);\n } else {\n this.log('❌ Max reconnection attempts reached', 'error');\n }\n } finally {\n this.isConnecting = false;\n }\n }\n\n /**\n * Build hub URL\n */\n private buildHubUrl(): string {\n let baseUrl = this.config.baseUrl;\n\n if (!baseUrl && typeof window !== 'undefined') {\n baseUrl = window.location.origin;\n }\n\n if (!baseUrl) {\n throw new Error('SignalR baseUrl is required outside browser runtimes');\n }\n\n return `${baseUrl}${this.config.hubPath}`;\n }\n\n /**\n * Setup connection lifecycle handlers\n */\n private setupConnectionHandlers(): void {\n if (!this.connection) return;\n\n this.connection.onreconnecting((error) => {\n this.log(`🔄 Reconnecting... ${error?.message || ''}`);\n });\n\n this.connection.onreconnected((connectionId) => {\n this.log(`✅ Reconnected (ID: ${connectionId})`);\n this.reconnectAttempts = 0;\n });\n\n this.connection.onclose((error) => {\n this.log(`🔌 Connection closed: ${error?.message || 'No error'}`);\n\n // Auto-reconnect if we have a token and it wasn't a manual disconnect\n if (this.accessToken && error) {\n setTimeout(() => {\n this.connect(this.accessToken);\n }, 5000);\n }\n });\n\n // Re-register all event handlers\n this.eventHandlers.forEach((handlers, eventName) => {\n this.connection!.on(eventName, (event: unknown) => {\n handlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n this.log(`❌ Error in ${eventName} handler: ${err}`, 'error');\n }\n });\n });\n });\n }\n\n /**\n * Disconnect from SignalR hub\n */\n async disconnect(): Promise<void> {\n if (this.connection) {\n this.log('🔌 Disconnecting...');\n await this.connection.stop();\n this.connection = null;\n this.accessToken = null;\n this.reconnectAttempts = 0;\n }\n }\n\n /**\n * Register event handler\n */\n on<T = unknown>(eventName: string, handler: SignalREventHandler<T>): () => void {\n // Add to handlers map\n if (!this.eventHandlers.has(eventName)) {\n this.eventHandlers.set(eventName, new Set());\n }\n this.eventHandlers.get(eventName)!.add(handler as SignalREventHandler);\n\n // If already connected, register immediately\n if (this.connection) {\n this.connection.on(eventName, handler);\n }\n\n // Return unsubscribe function\n return () => {\n this.eventHandlers.get(eventName)?.delete(handler as SignalREventHandler);\n this.connection?.off(eventName, handler);\n };\n }\n\n /**\n * Invoke hub method\n */\n async invoke<T = void>(methodName: string, ...args: unknown[]): Promise<T> {\n if (!this.connection || this.connection.state !== 'Connected') {\n throw new Error('SignalR not connected');\n }\n return this.connection.invoke<T>(methodName, ...args);\n }\n\n /**\n * Get current connection state\n */\n get connectionState(): SignalRConnectionState {\n return (this.connection?.state as SignalRConnectionState) || 'Disconnected';\n }\n\n /**\n * Check if connected\n */\n get isConnected(): boolean {\n return this.connection?.state === 'Connected';\n }\n\n /**\n * Get connection ID\n */\n get connectionId(): string | null {\n return this.connection?.connectionId || null;\n }\n\n /**\n * Cleanup resources\n */\n dispose(): void {\n if (this.visibilityHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.visibilityHandler);\n }\n this.disconnect();\n this.eventHandlers.clear();\n }\n\n /**\n * Log message\n */\n private log(message: string, level: 'info' | 'warn' | 'error' = 'info'): void {\n if (!this.config.verbose && level === 'info') return;\n\n const prefix = '[SignalR]';\n switch (level) {\n case 'warn':\n console.warn(prefix, message);\n break;\n case 'error':\n console.error(prefix, message);\n break;\n default:\n console.log(prefix, message);\n }\n }\n}\n\n/**\n * Create Identity SignalR Client\n * \n * Factory function to create a SignalR client for identity hub.\n */\nexport function createIdentitySignalRClient(\n options: Omit<SignalRClientConfig, 'hubPath'> = {}\n): SignalRClient {\n return new SignalRClient({\n ...options,\n hubPath: '/hubs/identity',\n });\n}\n\n/**\n * Identity SignalR Client\n * \n * Specialized client for identity context changes.\n */\nexport class IdentitySignalRClient extends SignalRClient {\n private identityHandlers: IdentityContextChangeHandler[] = [];\n\n constructor(options: Omit<SignalRClientConfig, 'hubPath'> = {}) {\n super({\n ...options,\n hubPath: '/hubs/identity',\n });\n\n // Register identity context change handler\n this.on<IdentityContextChangedEvent>('IdentityContextChanged', (event) => {\n this.identityHandlers.forEach((handler) => {\n try {\n handler(event);\n } catch (error) {\n console.error('Error in identity context change handler:', error);\n }\n });\n });\n }\n\n /**\n * Add handler for identity context changes\n */\n onIdentityContextChanged(handler: IdentityContextChangeHandler): () => void {\n this.identityHandlers.push(handler);\n\n return () => {\n const index = this.identityHandlers.indexOf(handler);\n if (index > -1) {\n this.identityHandlers.splice(index, 1);\n }\n };\n }\n}\n\n/**\n * Singleton identity client instance\n */\nlet identityClientInstance: IdentitySignalRClient | null = null;\n\n/**\n * Get or create singleton identity SignalR client\n */\nexport function getIdentitySignalRClient(\n options: Omit<SignalRClientConfig, 'hubPath'> = {}\n): IdentitySignalRClient {\n if (!identityClientInstance) {\n identityClientInstance = new IdentitySignalRClient(options);\n }\n return identityClientInstance;\n}\n\n/**\n * Initialize SignalR with access token\n */\nexport async function initializeSignalR(\n accessToken: string | null,\n options: Omit<SignalRClientConfig, 'hubPath'> = {}\n): Promise<IdentitySignalRClient> {\n if (typeof window === 'undefined') {\n throw new Error('SignalR can only be initialized on the client');\n }\n\n const client = getIdentitySignalRClient(options);\n await client.connect(accessToken);\n return client;\n}\n\n/**\n * Cleanup SignalR connection\n */\nexport async function cleanupSignalR(): Promise<void> {\n if (identityClientInstance) {\n await identityClientInstance.disconnect();\n identityClientInstance.dispose();\n identityClientInstance = null;\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { TenantProvider, configureTenantEndpoints, initializeTenantStore, useCurrentOrganization, useCurrentTenant, useOrganization, useTenant, useTenantStore, useTenantSwitcher } from "../tenant-BErqEENp.js";
1
+ import { TenantProvider, configureTenantClient, configureTenantEndpoints, getTenantCookieName, initializeTenantStore, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetTenantClientConfig, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useOrganization, useTenant, useTenantData, useTenantStore, useTenantSwitcher } from "../tenant-DfLemb6n.js";
2
2
 
3
- export { TenantProvider, configureTenantEndpoints, initializeTenantStore, useCurrentOrganization, useCurrentTenant, useOrganization, useTenant, useTenantStore, useTenantSwitcher };
3
+ export { TenantProvider, configureTenantClient, configureTenantEndpoints, getTenantCookieName, initializeTenantStore, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetTenantClientConfig, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useOrganization, useTenant, useTenantData, useTenantStore, useTenantSwitcher };
@@ -1,5 +1,5 @@
1
- import "../logging-_h2mi3L9.js";
2
- import "../redis-session-storage.server-D0-72FV-.js";
3
- import { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, setActiveTenant, setCurrentTenant } from "../server-Ce9jQRdL.js";
1
+ import "../logging-DviiAkLx.js";
2
+ import "../redis-session-storage.server-v2VcpFsQ.js";
3
+ import { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, configureTenantResolution, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, resetTenantResolutionConfig, setActiveTenant, setCurrentTenant } from "../server-Ca-3DJf2.js";
4
4
 
5
- export { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, setActiveTenant, setCurrentTenant };
5
+ export { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, configureTenantResolution, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, resetTenantResolutionConfig, setActiveTenant, setCurrentTenant };
@@ -4,7 +4,7 @@
4
4
  * React context for tenant management.
5
5
  */
6
6
  import { type ReactNode } from 'react';
7
- import type { OrganizationData, TenantContextType, TenantMembership } from './types';
7
+ import type { OrganizationData, TenantContextType, TenantData, TenantMembership } from './types';
8
8
  interface TenantProviderProps {
9
9
  children: ReactNode;
10
10
  initialTenant?: string | null;
@@ -29,12 +29,28 @@ export declare function useTenantSwitcher(): {
29
29
  isLoading: boolean;
30
30
  availableTenants: string[];
31
31
  };
32
+ /**
33
+ * Hook for current tenant data
34
+ */
35
+ export declare function useCurrentTenantData(): TenantData | null;
36
+ /**
37
+ * Hook for tenant data operations
38
+ */
39
+ export declare function useTenantData(): {
40
+ tenantData: TenantData | null;
41
+ refreshTenantData: () => void;
42
+ isLoading: boolean;
43
+ };
32
44
  /**
33
45
  * Hook for current organization
46
+ *
47
+ * @deprecated Use useCurrentTenantData instead.
34
48
  */
35
49
  export declare function useCurrentOrganization(): OrganizationData | null;
36
50
  /**
37
51
  * Hook for organization operations
52
+ *
53
+ * @deprecated Use useTenantData instead.
38
54
  */
39
55
  export declare function useOrganization(): {
40
56
  organization: OrganizationData | null;
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-context.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant-context.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAwC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIrF,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,SAAS,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,aAAoB,EACpB,cAAmB,EACnB,kBAAuB,EACvB,cAAc,GACf,EAAE,mBAAmB,2CA+GrB;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,iBAAiB,CAQ7C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAGhD;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;EAGhC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,GAAG,IAAI,CAGhE;AAED;;GAEG;AACH,wBAAgB,eAAe;;;;EAQ9B"}
1
+ {"version":3,"file":"tenant-context.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant-context.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAwC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIjG,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,SAAS,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,aAAoB,EACpB,cAAmB,EACnB,kBAAuB,EACvB,cAAc,GACf,EAAE,mBAAmB,2CA0HrB;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,iBAAiB,CAQ7C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAGhD;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;EAGhC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,aAAa;;;;EAQ5B;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,GAAG,IAAI,CAGhE;AAED;;;;GAIG;AACH,wBAAgB,eAAe;;;;EAQ9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-cookie.server.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant-cookie.server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC;AAmBD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS9E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKvE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAKzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAKtE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C"}
1
+ {"version":3,"file":"tenant-cookie.server.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant-cookie.server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC;AAgCD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM9E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKvE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAKzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAKtE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C"}
@@ -1,38 +1,84 @@
1
1
  /**
2
2
  * Tenant Store (Zustand)
3
3
  *
4
- * Client-side state management for tenant and organization data.
4
+ * Client-side state management for tenant data.
5
5
  */
6
- import type { OrganizationData, TenantMembership } from './types';
7
- interface TenantState {
6
+ import type { OrganizationData, TenantData, TenantMembership } from './types';
7
+ export interface TenantDataFetcherContext {
8
+ tenantId: string;
9
+ endpoint: string;
10
+ fetch: typeof fetch;
11
+ }
12
+ export interface TenantSwitchContext {
13
+ tenantId: string;
14
+ endpoint: string;
15
+ fetch: typeof fetch;
16
+ currentTenant: string | null;
17
+ }
18
+ export interface TenantSwitchResult {
19
+ success: boolean;
20
+ tenantData?: TenantData | null;
21
+ reload?: boolean;
22
+ error?: unknown;
23
+ }
24
+ export interface TenantClientConfig {
25
+ tenantDataEndpoint?: string;
26
+ /** @deprecated Use tenantDataEndpoint instead. */
27
+ organizationEndpoint?: string;
28
+ tenantSwitchEndpoint?: string;
29
+ tenantCookieName?: string;
30
+ fetchTenantData?: (context: TenantDataFetcherContext) => Promise<TenantData | null>;
31
+ switchTenant?: (context: TenantSwitchContext) => Promise<TenantSwitchResult>;
32
+ reloadOnSwitch?: boolean;
33
+ }
34
+ export interface TenantState {
8
35
  currentTenant: string | null;
9
36
  availableTenants: string[];
10
37
  memberships: Map<string, TenantMembership>;
38
+ tenantData: Map<string, TenantData>;
39
+ /** @deprecated Use tenantData instead. */
11
40
  organizations: Map<string, OrganizationData>;
12
41
  isLoading: boolean;
13
42
  isSwitching: boolean;
14
43
  setCurrentTenant: (tenantId: string | null) => void;
15
44
  setAvailableTenants: (tenants: string[]) => void;
16
45
  setMemberships: (memberships: TenantMembership[]) => void;
46
+ setTenantData: (tenantId: string, data: TenantData) => void;
47
+ addTenantData: (tenantId: string, data: TenantData) => void;
48
+ /** @deprecated Use setTenantData instead. */
17
49
  setOrganization: (tenantId: string, data: OrganizationData) => void;
50
+ /** @deprecated Use addTenantData instead. */
18
51
  addOrganization: (tenantId: string, data: OrganizationData) => void;
19
52
  setLoading: (loading: boolean) => void;
20
53
  setSwitching: (switching: boolean) => void;
54
+ fetchTenantData: (tenantId: string) => Promise<void>;
55
+ /** @deprecated Use fetchTenantData instead. */
21
56
  fetchOrganization: (tenantId: string) => Promise<void>;
22
57
  switchTenant: (tenantId: string) => Promise<void>;
23
58
  getMembership: (tenantId: string) => TenantMembership | null;
24
59
  getCurrentMembership: () => TenantMembership | null;
25
60
  getTenantName: (tenantId: string) => string;
61
+ getTenantData: (tenantId: string) => TenantData | null;
62
+ getCurrentTenantData: () => TenantData | null;
63
+ /** @deprecated Use getTenantData instead. */
26
64
  getOrganization: (tenantId: string) => OrganizationData | null;
65
+ /** @deprecated Use getCurrentTenantData instead. */
27
66
  getCurrentOrganization: () => OrganizationData | null;
28
67
  }
29
68
  /**
30
- * Configure tenant store endpoints
69
+ * Configure tenant client behavior for any backend contract.
31
70
  */
32
- export declare function configureTenantEndpoints(config: {
33
- organizationEndpoint?: string;
34
- tenantSwitchEndpoint?: string;
35
- }): void;
71
+ export declare function configureTenantClient(config: TenantClientConfig): void;
72
+ /**
73
+ * Configure tenant store endpoints.
74
+ *
75
+ * @deprecated Use configureTenantClient for endpoint and contract customization.
76
+ */
77
+ export declare function configureTenantEndpoints(config: TenantClientConfig): void;
78
+ export declare function getTenantCookieName(): string;
79
+ export declare function resetTenantClientConfig(): void;
80
+ export declare function normalizeTenantDataPayload(payload: unknown): TenantData | null;
81
+ export declare function normalizeTenantSwitchPayload(payload: unknown): TenantSwitchResult;
36
82
  export declare const useTenantStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<TenantState>, "setState" | "devtools"> & {
37
83
  setState(partial: TenantState | Partial<TenantState> | ((state: TenantState) => TenantState | Partial<TenantState>), replace?: false | undefined, action?: (string | {
38
84
  [x: string]: unknown;
@@ -54,5 +100,4 @@ export declare const useTenantStore: import("zustand").UseBoundStore<Omit<import
54
100
  * Initialize store with server data
55
101
  */
56
102
  export declare function initializeTenantStore(currentTenant: string | null, availableTenants: string[], memberships?: TenantMembership[]): void;
57
- export {};
58
103
  //# sourceMappingURL=tenant-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-store.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAElE,UAAU,WAAW;IAEnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC3C,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IAGrB,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACpD,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC1D,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpE,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpE,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,YAAY,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAG3C,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAGlD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAC7D,oBAAoB,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;IACpD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAC/D,sBAAsB,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;CACvD;AAQD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,QAOA;AAED,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;EA4I1B,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,gBAAgB,EAAE,MAAM,EAAE,EAC1B,WAAW,CAAC,EAAE,gBAAgB,EAAE,QAQjC"}
1
+ {"version":3,"file":"tenant-store.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE9E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,KAAK,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kDAAkD;IAClD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACpF,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAE1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC3C,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACpC,0CAA0C;IAC1C,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IAGrB,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACpD,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC1D,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5D,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5D,6CAA6C;IAC7C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpE,6CAA6C;IAC7C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpE,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,YAAY,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAG3C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,+CAA+C;IAC/C,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAGlD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAC7D,oBAAoB,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;IACpD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,CAAC;IACvD,oBAAoB,EAAE,MAAM,UAAU,GAAG,IAAI,CAAC;IAC9C,6CAA6C;IAC7C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAC/D,oDAAoD;IACpD,sBAAsB,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;CACvD;AAYD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAmBtE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAEzE;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAO9C;AAmBD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAe9E;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAkBjF;AAyBD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;EAwK1B,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,gBAAgB,EAAE,MAAM,EAAE,EAC1B,WAAW,CAAC,EAAE,gBAAgB,EAAE,QAQjC"}
@@ -3,18 +3,37 @@
3
3
  *
4
4
  * Server-side tenant management.
5
5
  */
6
+ import type { SessionData } from '../auth/types';
6
7
  /**
7
8
  * Identity context fetcher type (to avoid circular dependency)
8
9
  */
9
10
  export type IdentityContextFetcher = (request: Request) => Promise<{
10
11
  memberships?: Array<{
11
- tenantId: string;
12
+ tenantId?: string;
13
+ id?: string;
14
+ [key: string]: unknown;
12
15
  }>;
16
+ [key: string]: unknown;
13
17
  } | null>;
18
+ export interface TenantResolutionContext {
19
+ request: Request;
20
+ session: SessionData;
21
+ identityContext: Awaited<ReturnType<IdentityContextFetcher>>;
22
+ }
23
+ export interface TenantResolutionConfig {
24
+ identityContextFetcher?: IdentityContextFetcher;
25
+ resolveInitialTenant?: (context: TenantResolutionContext) => Promise<string | null> | string | null;
26
+ resolveAvailableTenants?: (context: TenantResolutionContext) => Promise<string[]> | string[];
27
+ }
14
28
  /**
15
29
  * Configure identity context fetcher
16
30
  */
17
31
  export declare function configureIdentityContextFetcher(fetcher: IdentityContextFetcher): void;
32
+ /**
33
+ * Configure tenant resolution for custom backend identity contracts.
34
+ */
35
+ export declare function configureTenantResolution(config: TenantResolutionConfig): void;
36
+ export declare function resetTenantResolutionConfig(): void;
18
37
  /**
19
38
  * Get current active tenant from cookie
20
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.server.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant.server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;IACjE,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3C,GAAG,IAAI,CAAC,CAAC;AAIV;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAErF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAW/E;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuB3F;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAuB7E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBjE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA4BxD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAK3D"}
1
+ {"version":3,"file":"tenant.server.d.ts","sourceRoot":"","sources":["../../src/tenant/tenant.server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;IACjE,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IAChF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,GAAG,IAAI,CAAC,CAAC;AAEV,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC;CAC9D;AAED,MAAM,WAAW,sBAAsB;IACrC,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IACpG,uBAAuB,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CAC9F;AAcD;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAErF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAU9E;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAUlD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAW/E;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkB3F;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkB7E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBjE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA4BxD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAK3D"}