@fayz-ai/admin 0.49.0 → 0.51.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 (29) hide show
  1. package/dist/ScheduleEditor-6YFOBHAE.js +6 -0
  2. package/dist/{ScheduleEditor-BXWJ7CMI.js.map → ScheduleEditor-6YFOBHAE.js.map} +1 -1
  3. package/dist/SubscriptionPage-DI6UV5LF.js +8 -0
  4. package/dist/{SubscriptionPage-VBDDRSVW.js.map → SubscriptionPage-DI6UV5LF.js.map} +1 -1
  5. package/dist/app/admin-app.d.ts.map +1 -1
  6. package/dist/app/config.d.ts +6 -0
  7. package/dist/app/config.d.ts.map +1 -1
  8. package/dist/billing/index.js +3 -3
  9. package/dist/{chunk-2Q6QHTZV.js → chunk-3S7UULIC.js} +4 -4
  10. package/dist/{chunk-2Q6QHTZV.js.map → chunk-3S7UULIC.js.map} +1 -1
  11. package/dist/{chunk-KVIINVY6.js → chunk-4RKG7YH5.js} +3 -3
  12. package/dist/{chunk-KVIINVY6.js.map → chunk-4RKG7YH5.js.map} +1 -1
  13. package/dist/{chunk-OEY3V6J3.js → chunk-DASJ4UF3.js} +3 -3
  14. package/dist/{chunk-OEY3V6J3.js.map → chunk-DASJ4UF3.js.map} +1 -1
  15. package/dist/{chunk-ZMP52ZHM.js → chunk-EOYE3ZAC.js} +3 -3
  16. package/dist/{chunk-ZMP52ZHM.js.map → chunk-EOYE3ZAC.js.map} +1 -1
  17. package/dist/{chunk-F346TYKO.js → chunk-TAN7UGC2.js} +5 -5
  18. package/dist/{chunk-F346TYKO.js.map → chunk-TAN7UGC2.js.map} +1 -1
  19. package/dist/{chunk-GZWX4ZIK.js → chunk-XQM74EP4.js} +37 -3
  20. package/dist/chunk-XQM74EP4.js.map +1 -0
  21. package/dist/data/client.d.ts +19 -0
  22. package/dist/data/client.d.ts.map +1 -1
  23. package/dist/index.js +14 -13
  24. package/dist/index.js.map +1 -1
  25. package/dist/org/index.js +2 -2
  26. package/package.json +7 -7
  27. package/dist/ScheduleEditor-BXWJ7CMI.js +0 -6
  28. package/dist/SubscriptionPage-VBDDRSVW.js +0 -8
  29. package/dist/chunk-GZWX4ZIK.js.map +0 -1
@@ -14,6 +14,31 @@ function requestUrl(input) {
14
14
  function isEdgeFunctionCall(input) {
15
15
  return requestUrl(input).includes("/functions/v1/");
16
16
  }
17
+ var _serviceUrl = null;
18
+ var _routes = {};
19
+ async function setServiceUrl(url, fetcher = (...args) => fetch(...args)) {
20
+ _serviceUrl = url ? url.replace(/\/+$/u, "") : null;
21
+ _routes = {};
22
+ if (!_serviceUrl) return;
23
+ try {
24
+ const response = await fetcher(`${_serviceUrl}/v1/service/routes`);
25
+ if (!response.ok) return;
26
+ const body = await response.json();
27
+ const table = {};
28
+ for (const [slug, path] of Object.entries(body.routes ?? {})) {
29
+ if (typeof path === "string" && path.startsWith("/v1/")) table[slug] = path;
30
+ }
31
+ _routes = Object.freeze(table);
32
+ } catch {
33
+ }
34
+ }
35
+ function serviceUrlFor(input) {
36
+ if (!_serviceUrl) return null;
37
+ const url = requestUrl(input);
38
+ const match = /\/functions\/v1\/([a-z0-9-]+)(\?.*)?$/u.exec(url);
39
+ const route = match ? _routes[match[1]] : void 0;
40
+ return route ? `${_serviceUrl}${route}${match?.[2] ?? ""}` : null;
41
+ }
17
42
  function createFayzSupabaseClient(url, anonKey) {
18
43
  if (_client) return _client;
19
44
  if (!url || !anonKey) {
@@ -34,6 +59,15 @@ function createFayzSupabaseClient(url, anonKey) {
34
59
  // `x-fayz-unit` is in the dedupe vary list. Without that, two identical
35
60
  // URLs under different units collapse into one response.
36
61
  fetch: (input, init = {}) => {
62
+ const serviceTarget = serviceUrlFor(input);
63
+ if (serviceTarget) {
64
+ const headers2 = new Headers(init.headers);
65
+ const unit2 = getActiveUnitId();
66
+ const tenant2 = getActiveTenantId();
67
+ if (unit2) headers2.set("x-fayz-unit", unit2);
68
+ if (tenant2) headers2.set("x-fayz-tenant", tenant2);
69
+ return fetch(serviceTarget, { ...init, headers: headers2 });
70
+ }
37
71
  if (isEdgeFunctionCall(input)) return deduped(input, init);
38
72
  const unit = getActiveUnitId();
39
73
  const tenant = getActiveTenantId();
@@ -106,6 +140,6 @@ var useOrganizationStore = create((set) => ({
106
140
  }));
107
141
  var getSupabaseClientOptional = () => getSupabaseClientOptional$1();
108
142
 
109
- export { createFayzSupabaseClient, getFayzSupabaseClient, getFayzSupabaseClientOptional, getPersistedOrgId, getSupabaseClientOptional, persistOrgId, useOrganizationStore };
110
- //# sourceMappingURL=chunk-GZWX4ZIK.js.map
111
- //# sourceMappingURL=chunk-GZWX4ZIK.js.map
143
+ export { createFayzSupabaseClient, getFayzSupabaseClient, getFayzSupabaseClientOptional, getPersistedOrgId, getSupabaseClientOptional, persistOrgId, setServiceUrl, useOrganizationStore };
144
+ //# sourceMappingURL=chunk-XQM74EP4.js.map
145
+ //# sourceMappingURL=chunk-XQM74EP4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data/client.ts","../src/org/store.ts","../src/lib/supabase.ts"],"names":["headers","unit","tenant","_getOpt"],"mappings":"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","file":"chunk-XQM74EP4.js","sourcesContent":["import { createClient, type SupabaseClient } from '@supabase/supabase-js'\nimport { setGlobalSupabaseClient, getActiveUnitId, getActiveTenantId } from '@fayz-ai/core'\nimport { createDedupedFetch } from '@fayz-ai/sdk'\n\nlet _client: SupabaseClient | null = null\n\n/**\n * Para onde a requisição vai, nos três formatos que `fetch` aceita.\n *\n * `input` pode ser uma string, uma URL ou um Request — e ler `.url` de uma\n * string devolve `undefined` em silêncio, que é como um filtro destes deixa\n * passar exatamente o que devia barrar.\n */\nexport function requestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input\n if (input instanceof URL) return input.toString()\n return input?.url ?? ''\n}\n\n/** O caminho que o Supabase dá a toda função de borda. Exportada para o teste. */\nexport function isEdgeFunctionCall(input: RequestInfo | URL): boolean {\n return requestUrl(input).includes('/functions/v1/')\n}\n\nlet _serviceUrl: string | null = null\nlet _routes: Readonly<Record<string, string>> = {}\n\n/**\n * Where the integration service answers (ADR 0003 phase 2), and which former\n * edge functions it is READY to answer for.\n *\n * The list comes from the service itself (`GET /v1/service/routes`): a function\n * appears there only once its module is mounted and its keys are configured.\n * Until the list arrives, and for anything not on it, calls stay on the edge\n * functions, so a function moves only when the service can really do its job.\n * Null keeps everything on the edge.\n */\nexport async function setServiceUrl(\n url: string | null | undefined,\n fetcher: typeof fetch = (...args) => fetch(...args),\n): Promise<void> {\n _serviceUrl = url ? url.replace(/\\/+$/u, '') : null\n _routes = {}\n if (!_serviceUrl) return\n try {\n const response = await fetcher(`${_serviceUrl}/v1/service/routes`)\n if (!response.ok) return\n const body = (await response.json()) as { routes?: Record<string, unknown> }\n const table: Record<string, string> = {}\n for (const [slug, path] of Object.entries(body.routes ?? {})) {\n if (typeof path === 'string' && path.startsWith('/v1/')) table[slug] = path\n }\n _routes = Object.freeze(table)\n } catch {\n // The service is unreachable: everything stays on the edge functions.\n }\n}\n\n/** The routes the service answered with, for tests and diagnostics. */\nexport function serviceRoutes(): Readonly<Record<string, string>> {\n return _routes\n}\n\n/**\n * The service URL for an edge-function call, or null when it stays an edge\n * function. `/functions/v1/<slug>` and anything after it (a query) map to the\n * route; an unlisted slug is left alone.\n */\nexport function serviceUrlFor(input: RequestInfo | URL): string | null {\n if (!_serviceUrl) return null\n const url = requestUrl(input)\n const match = /\\/functions\\/v1\\/([a-z0-9-]+)(\\?.*)?$/u.exec(url)\n const route = match ? _routes[match[1]!] : undefined\n return route ? `${_serviceUrl}${route}${match?.[2] ?? ''}` : null\n}\n\n/**\n * Create (and cache) the Supabase client for the Fayz app.\n * Also registers it as the global client in @fayz-ai/core so data providers\n * can resolve it without prop-drilling.\n *\n * Idempotent — subsequent calls with the same URL return the cached client.\n */\nexport function createFayzSupabaseClient(url: string, anonKey: string): SupabaseClient {\n if (_client) return _client\n\n if (!url || !anonKey) {\n throw new Error(\n '[@fayz-ai/admin] Supabase URL and anon key are required. ' +\n 'Pass supabaseUrl and supabaseAnonKey to createFayzApp.',\n )\n }\n\n // Every read goes through this client — the one place that can see two\n // components asking the same thing at the same instant.\n const deduped = createDedupedFetch()\n\n _client = createClient(url, anonKey, {\n auth: { autoRefreshToken: true, persistSession: true },\n global: {\n // The active unit rides on every request so the DATABASE can stamp a\n // write with it (041's trigger reads this header). Reads are narrowed by\n // an explicit filter, not by this — a header cannot be trusted to narrow,\n // and it must never be able to widen: the policies resolve unit access\n // through `public.user_unit_ids()`, never through what was sent here.\n //\n // `x-fayz-unit` is in the dedupe vary list. Without that, two identical\n // URLs under different units collapse into one response.\n fetch: (input: RequestInfo | URL, init: RequestInit = {}) => {\n // Estes cabeçalhos são para o BANCO, e só para ele. Uma função de borda\n // recebe o tenant no corpo (`tenantId`) e nunca leu nenhum dos dois — o\n // que ela faz com um cabeçalho desconhecido é RECUSAR O PREFLIGHT, e o\n // navegador então bloqueia o POST antes de ele sair. Nenhuma requisição\n // chega ao log, e quem está usando vê a palavra \"CORS\".\n //\n // As vinte funções deste repositório declaram listas fixas de\n // `Access-Control-Allow-Headers` e nenhuma delas cita `x-fayz-tenant`.\n // Mandar o cabeçalho para lá não compra nada e derruba todas de uma vez.\n // A function the integration service hosts goes there instead, and it\n // DOES take the tenant and unit headers: its CORS answers whatever the\n // browser asks to send, and it acts in the tenant the caller named.\n const serviceTarget = serviceUrlFor(input)\n if (serviceTarget) {\n const headers = new Headers(init.headers)\n const unit = getActiveUnitId()\n const tenant = getActiveTenantId()\n if (unit) headers.set('x-fayz-unit', unit)\n if (tenant) headers.set('x-fayz-tenant', tenant)\n return fetch(serviceTarget, { ...init, headers })\n }\n if (isEdgeFunctionCall(input)) return deduped(input, init)\n\n const unit = getActiveUnitId()\n // `x-fayz-tenant` rides the same way, for the reason 145 spells out:\n // the archetype policies resolve tenant through app.current_tenant_id(),\n // which knew only the signed JWT claim (nobody mints one) or \"your only\n // account\". A user with two accounts therefore read NOTHING from\n // public.people / orders / products — silently, and long before any\n // screen moved. This is the app finally saying which account it is in.\n //\n // Same rule as the unit header, and 145 enforces it: the value only\n // CHOOSES among the accounts the user already belongs to, validated\n // against app.memberships. It narrows; it can never widen.\n const tenant = getActiveTenantId()\n if (!unit && !tenant) return deduped(input, init)\n const headers = new Headers(init.headers)\n if (unit) headers.set('x-fayz-unit', unit)\n if (tenant) headers.set('x-fayz-tenant', tenant)\n return deduped(input, { ...init, headers })\n },\n },\n })\n\n // Register globally so @fayz-ai/core data providers can use it\n setGlobalSupabaseClient(_client)\n\n return _client\n}\n\n/** Get the cached client — throws if not initialised */\nexport function getFayzSupabaseClient(): SupabaseClient {\n if (!_client) {\n throw new Error(\n '[@fayz-ai/admin] Supabase client not initialised. Call createFayzApp with supabaseUrl and supabaseAnonKey first.',\n )\n }\n return _client\n}\n\n/** Safe getter — returns null if not initialised (mock/offline mode) */\nexport function getFayzSupabaseClientOptional(): SupabaseClient | null {\n return _client\n}\n","import { create } from 'zustand'\nimport { setActiveTenantId, type Organization, type OrgMember, type OrgMembership } from '@fayz-ai/core'\n\nconst STORAGE_KEY = 'fayz:current-org'\n\n// ---------------------------------------------------------------------------\n// Persistence helpers\n// ---------------------------------------------------------------------------\n\nfunction getPersistedOrgId(): string | null {\n try {\n if (typeof localStorage === 'undefined') return null\n return localStorage.getItem(STORAGE_KEY)\n } catch {\n return null\n }\n}\n\nfunction persistOrgId(orgId: string | null): void {\n try {\n if (typeof localStorage === 'undefined') return\n if (orgId) {\n localStorage.setItem(STORAGE_KEY, orgId)\n } else {\n localStorage.removeItem(STORAGE_KEY)\n }\n } catch {\n // ignore\n }\n}\n\n// ---------------------------------------------------------------------------\n// Store interface\n// ---------------------------------------------------------------------------\n\nexport interface OrgStore {\n currentOrg: Organization | null\n userOrgs: OrgMembership[]\n members: OrgMember[]\n /** Person `kind`s that make up the team (from config.team.personKinds). Drives\n * the Person-first Team screen; empty = legacy membership-only mode. */\n teamPersonKinds: string[]\n loading: boolean\n\n /**\n * A conta ativa, e a ESCOLHA que ela representa: persiste o pino.\n *\n * Use quando alguém decidiu — a troca de conta, a resolução do boot. Para\n * apenas PINTAR o que já se sabia, use `paintCurrentOrg`.\n */\n setCurrentOrg: (org: Organization | null) => void\n /**\n * Pinta a conta sem gravar o pino.\n *\n * O snapshot repinta a última conta conhecida antes de o primeiro filho\n * renderizar, para ninguém ver um quadro sem org. Isso é CACHE, não\n * decisão — e enquanto ele gravava o pino, vencia o\n * `decideWorkspaceChoice`: quem usa duas contas ficava preso na última que\n * o snapshot viu, e nada escolhido sobrevivia ao boot.\n */\n paintCurrentOrg: (org: Organization | null) => void\n setUserOrgs: (orgs: OrgMembership[]) => void\n setMembers: (members: OrgMember[]) => void\n setTeamPersonKinds: (kinds: string[]) => void\n setLoading: (loading: boolean) => void\n reset: () => void\n}\n\nexport const useOrganizationStore = create<OrgStore>((set) => ({\n currentOrg: null,\n userOrgs: [],\n members: [],\n teamPersonKinds: [],\n loading: false,\n\n setCurrentOrg: (org) => {\n setActiveTenantId(org?.id)\n persistOrgId(org?.id ?? null)\n set({ currentOrg: org })\n },\n\n // Sem `persistOrgId`: é a única diferença, e é toda a diferença.\n paintCurrentOrg: (org) => {\n setActiveTenantId(org?.id)\n set({ currentOrg: org })\n },\n setUserOrgs: (orgs) => set({ userOrgs: orgs }),\n setMembers: (members) => set({ members }),\n setTeamPersonKinds: (kinds) => set({ teamPersonKinds: kinds }),\n setLoading: (loading) => set({ loading }),\n reset: () => {\n setActiveTenantId(undefined)\n // NOTE: do NOT clear the persisted org id here. The org providers call\n // reset() whenever the auth store transiently reports `user === null` —\n // which happens on every fresh load while the Supabase session hydrates\n // asynchronously. Wiping 'fayz:current-org' at that moment drops a\n // multi-org user's workspace selection BEFORE loadOrgs can read it back,\n // so the app always falls to memberships[0] on reload (single-org users\n // never noticed). The pin is a last-selected hint that's re-validated\n // against the fresh membership list on load, so it's safe to keep across\n // sign-out too (a mismatching pin just falls back to memberships[0]).\n set({ currentOrg: null, userOrgs: [], members: [], loading: false })\n },\n}))\n\nexport { getPersistedOrgId, persistOrgId }\n","// Shim → native Supabase client (unified singleton across shell + plugins).\nimport type { SupabaseClient } from '@supabase/supabase-js'\nimport { getSupabaseClientOptional as _getOpt } from '@fayz-ai/core'\nexport { createSupabaseProvider, setGlobalSupabaseClient } from '@fayz-ai/core'\n// @fayz-ai/core returns a loosely-typed client (no hard supabase coupling); the\n// shell does `.from(...)` against the single public client, so surface it as\n// the real client type.\nexport const getSupabaseClientOptional = (): SupabaseClient | null =>\n _getOpt() as unknown as SupabaseClient | null\nexport {\n getFayzSupabaseClient as getSupabaseClient,\n getFayzSupabaseClientOptional as getSupabaseClientSafe,\n createFayzSupabaseClient as createSupabaseClient,\n} from '../data/client'\nimport { getFayzSupabaseClient } from '../data/client'\n// Core tables now live in the public schema — the \"core\" client is just the\n// plain public client. Kept as a backward-compatible alias for call sites.\nexport const getCoreClient = getFayzSupabaseClient\nexport const getCoreSupabaseClient = getFayzSupabaseClient\nexport const getProjectSupabaseClient = getFayzSupabaseClient\nexport type { SupabaseClient }\n"]}
@@ -9,6 +9,25 @@ import { type SupabaseClient } from '@supabase/supabase-js';
9
9
  export declare function requestUrl(input: RequestInfo | URL): string;
10
10
  /** O caminho que o Supabase dá a toda função de borda. Exportada para o teste. */
11
11
  export declare function isEdgeFunctionCall(input: RequestInfo | URL): boolean;
12
+ /**
13
+ * Where the integration service answers (ADR 0003 phase 2), and which former
14
+ * edge functions it is READY to answer for.
15
+ *
16
+ * The list comes from the service itself (`GET /v1/service/routes`): a function
17
+ * appears there only once its module is mounted and its keys are configured.
18
+ * Until the list arrives, and for anything not on it, calls stay on the edge
19
+ * functions, so a function moves only when the service can really do its job.
20
+ * Null keeps everything on the edge.
21
+ */
22
+ export declare function setServiceUrl(url: string | null | undefined, fetcher?: typeof fetch): Promise<void>;
23
+ /** The routes the service answered with, for tests and diagnostics. */
24
+ export declare function serviceRoutes(): Readonly<Record<string, string>>;
25
+ /**
26
+ * The service URL for an edge-function call, or null when it stays an edge
27
+ * function. `/functions/v1/<slug>` and anything after it (a query) map to the
28
+ * route; an unlisted slug is left alone.
29
+ */
30
+ export declare function serviceUrlFor(input: RequestInfo | URL): string | null;
12
31
  /**
13
32
  * Create (and cache) the Supabase client for the Fayz app.
14
33
  * Also registers it as the global client in @fayz-ai/core so data providers
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/data/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAMzE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,CAI3D;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,OAAO,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CA8DrF;AAED,wDAAwD;AACxD,wBAAgB,qBAAqB,IAAI,cAAc,CAOtD;AAED,wEAAwE;AACxE,wBAAgB,6BAA6B,IAAI,cAAc,GAAG,IAAI,CAErE"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/data/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAMzE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,CAI3D;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,OAAO,CAEpE;AAKD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,OAAO,GAAE,OAAO,KAAmC,GAClD,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,uEAAuE;AACvE,wBAAgB,aAAa,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,GAAG,IAAI,CAMrE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CA0ErF;AAED,wDAAwD;AACxD,wBAAgB,qBAAqB,IAAI,cAAc,CAOtD;AAED,wEAAwE;AACxE,wBAAgB,6BAA6B,IAAI,cAAc,GAAG,IAAI,CAErE"}
package/dist/index.js CHANGED
@@ -1,24 +1,24 @@
1
1
  export { PersonTimeline, TimelineList, TimelineSkeleton, getTimelineSources, registerTimelineSource, unregisterTimelineSource, usePersonTimeline } from './chunk-E4MESMNR.js';
2
- import { useLimitGuard, invalidateLimit, useAccessOptional, useUpgradeModalStore, getLimitDeclaration, useLimit, featureDisplayName, PlanFeatureItem, usePresetLabel, useAppConfig, useOfferedPlugins, AccessProvider, CORE_LIMIT_DECLARATIONS, entityDerivedLimitDeclarations, useTenantLedIdentity, getPlanEntitlements, resolvePlanCurrency, useAppPreset, useAppTheme, clearAppConfigSnapshot, MODULE_FAMILIES, moduleFamilyOf, UPCOMING_MODULE_INFO } from './chunk-F346TYKO.js';
3
- export { AccessProvider, invalidateLimit, useAccess, useAccessOptional, useAppConfig, useLimit, useLimitGuard, useOfferedPlugins, usePresetLabel, useUpgradeModalStore } from './chunk-F346TYKO.js';
2
+ import { useLimitGuard, invalidateLimit, useAccessOptional, useUpgradeModalStore, getLimitDeclaration, useLimit, featureDisplayName, PlanFeatureItem, usePresetLabel, useAppConfig, useOfferedPlugins, AccessProvider, CORE_LIMIT_DECLARATIONS, entityDerivedLimitDeclarations, useTenantLedIdentity, getPlanEntitlements, resolvePlanCurrency, useAppPreset, useAppTheme, clearAppConfigSnapshot, MODULE_FAMILIES, moduleFamilyOf, UPCOMING_MODULE_INFO } from './chunk-TAN7UGC2.js';
3
+ export { AccessProvider, invalidateLimit, useAccess, useAccessOptional, useAppConfig, useLimit, useLimitGuard, useOfferedPlugins, usePresetLabel, useUpgradeModalStore } from './chunk-TAN7UGC2.js';
4
4
  export { clearRecentRecords, listRecentRecords, rememberVisit, subscribeRecentRecords, useOpenRecent, useRecentRecords, useRecordVisit } from './chunk-OD7P4L3D.js';
5
5
  import { useTranslation as useTranslation$1 } from './chunk-YUHCC7JY.js';
6
- import { resolvePlanBadge, TrialWidget } from './chunk-2Q6QHTZV.js';
7
- import { useBillingStore, packageFor, COMING_SOON_MODULES, moduleFitsTrades, TRADE_BY_APP, PRICE_BOOK, includedIn } from './chunk-OEY3V6J3.js';
8
- export { EXTRA_SEAT_PRICE, PRICE_BOOK, PRICING_PLANS, UNIT_TIERS, activeModuleKeys, billableModules, quote, quoteAll, unitFactor, useBillingStore } from './chunk-OEY3V6J3.js';
6
+ import { resolvePlanBadge, TrialWidget } from './chunk-3S7UULIC.js';
7
+ import { useBillingStore, packageFor, COMING_SOON_MODULES, moduleFitsTrades, TRADE_BY_APP, PRICE_BOOK, includedIn } from './chunk-DASJ4UF3.js';
8
+ export { EXTRA_SEAT_PRICE, PRICE_BOOK, PRICING_PLANS, UNIT_TIERS, activeModuleKeys, billableModules, quote, quoteAll, unitFactor, useBillingStore } from './chunk-DASJ4UF3.js';
9
9
  import { resolveEntityRoute, openEntity, entityRouteHasDetail, resolveEntityAnchor, setEntityRouteMap } from './chunk-P5UIGQFY.js';
10
10
  export { openEntity, resolveEntityAnchor, resolveEntityHref, resolveEntityRoute } from './chunk-P5UIGQFY.js';
11
11
  import { useAdminPath, navigateTo, normalizeAdminPath, routeScore, matchRoute } from './chunk-VX3WJLKK.js';
12
12
  export { navigateTo as adminNavigateTo, useAdminPath } from './chunk-VX3WJLKK.js';
13
13
  export { ImportWizard } from './chunk-5GCC7YCE.js';
14
- import { createArchetypeLookup, getPersonLookup } from './chunk-KVIINVY6.js';
15
- export { ScheduleDateExceptions, ScheduleEditor, ScheduleGridPanel, createArchetypeLookup, deleteSchedule, getPersonBookable, getPersonLookup, getScheduleBlockConfig, getSchedules, mergeBlockSettings, parseBlockSettings, registerPersonLookup, replaceWeeklySchedules, saveSchedule, setPersonBookable, setScheduleBlockConfig, subscribeScheduleBlockConfig } from './chunk-KVIINVY6.js';
16
- import { useUnitStore, useTenantOptional, fetchMemberUnits, UNIT_ACCESS_CHANGED, useOrgAdapter, useTenant, useWorkspaceSwitchingStore, searchWorkspaces, OrgMark, WorkspaceChooserGate, WorkspaceSwitchingHost, OrgProvider, useOrgAdapterOptional, dedup, bindUserToUnit, unbindUserFromUnit, useAppConfigStore, resolveAppId, createSupabaseOrgAdapter, createMockOrgAdapter, fetchUnitMembers, fetchMemberActivity, markWorkspaceSwitch, countUnboundMembers, bindAllMembersTo, setUnitModeRemote, fetchUserIdForPerson } from './chunk-ZMP52ZHM.js';
17
- export { ORG_CACHE_TTL_MS, OrgMark, OrgProvider, activePluginIds, clearOrgSnapshot, createMockOrgAdapter, createSupabaseOrgAdapter, dedup, hasPlugin, orgInitials, readOrgSnapshot, useAppConfigStore, useOrgAdapter, useOrgAdapterOptional, useTenant, useTenantOptional, useUnitStore } from './chunk-ZMP52ZHM.js';
14
+ import { createArchetypeLookup, getPersonLookup } from './chunk-4RKG7YH5.js';
15
+ export { ScheduleDateExceptions, ScheduleEditor, ScheduleGridPanel, createArchetypeLookup, deleteSchedule, getPersonBookable, getPersonLookup, getScheduleBlockConfig, getSchedules, mergeBlockSettings, parseBlockSettings, registerPersonLookup, replaceWeeklySchedules, saveSchedule, setPersonBookable, setScheduleBlockConfig, subscribeScheduleBlockConfig } from './chunk-4RKG7YH5.js';
16
+ import { useUnitStore, useTenantOptional, fetchMemberUnits, UNIT_ACCESS_CHANGED, useOrgAdapter, useTenant, useWorkspaceSwitchingStore, searchWorkspaces, OrgMark, WorkspaceChooserGate, WorkspaceSwitchingHost, OrgProvider, useOrgAdapterOptional, dedup, bindUserToUnit, unbindUserFromUnit, useAppConfigStore, resolveAppId, createSupabaseOrgAdapter, createMockOrgAdapter, fetchUnitMembers, fetchMemberActivity, markWorkspaceSwitch, countUnboundMembers, bindAllMembersTo, setUnitModeRemote, fetchUserIdForPerson } from './chunk-EOYE3ZAC.js';
17
+ export { ORG_CACHE_TTL_MS, OrgMark, OrgProvider, activePluginIds, clearOrgSnapshot, createMockOrgAdapter, createSupabaseOrgAdapter, dedup, hasPlugin, orgInitials, readOrgSnapshot, useAppConfigStore, useOrgAdapter, useOrgAdapterOptional, useTenant, useTenantOptional, useUnitStore } from './chunk-EOYE3ZAC.js';
18
18
  import { usePermissionOptional, usePermissionsStore, PermissionsProvider } from './chunk-UQ2NTFQC.js';
19
19
  export { PermissionsProvider, useHasPermission, usePermission, usePermissionOptional, usePermissions, usePermissionsStore } from './chunk-UQ2NTFQC.js';
20
- import { cn, getFayzSupabaseClientOptional, getSupabaseClientOptional as getSupabaseClientOptional$1, useOrganizationStore, createFayzSupabaseClient, getFayzSupabaseClient } from './chunk-GZWX4ZIK.js';
21
- export { createFayzSupabaseClient, getFayzSupabaseClient, getFayzSupabaseClientOptional, getPersistedOrgId, useOrganizationStore } from './chunk-GZWX4ZIK.js';
20
+ import { cn, getFayzSupabaseClientOptional, getSupabaseClientOptional as getSupabaseClientOptional$1, useOrganizationStore, createFayzSupabaseClient, setServiceUrl, getFayzSupabaseClient } from './chunk-XQM74EP4.js';
21
+ export { createFayzSupabaseClient, getFayzSupabaseClient, getFayzSupabaseClientOptional, getPersistedOrgId, useOrganizationStore } from './chunk-XQM74EP4.js';
22
22
  import * as React142 from 'react';
23
23
  import React142__default, { createContext, useMemo, useState, useRef, useCallback, useEffect, useContext, createElement } from 'react';
24
24
  import { Button, Input, SearchSelect, toast, usePageTrailParent, navigateToCrumb, PageHeader, ConfirmDialog, RowActions, useRowSelection, getLucideIcon, ListFilterBar, Dropdown, DropdownTrigger, Hint, cn as cn$1, DropdownContent, DropdownLabel, DropdownItem, DropdownSeparator, RefreshButton, PageHeaderActions, PageTabs, StatTiles, Card, BulkActionBar, DataTable, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalFooter, Badge, PersonAvatar, PageActionBar, Switch, ICON_MAP, Sheet, SheetContent, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, InfoHint, SheetBody, useIsWide, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, useTourStore, setTourNavigator, TourSpotlight, PracticeOverlay, Textarea, Wizard, SidebarOnboarding, OnboardingWidget, Skeleton, useLayoutStore, ChoiceSelect, usePublishPageInfo, ModalTask, Checkbox, ModalPortal, ModalOverlay, ModalBody, useSaveBar, useBackHandler, SubpageHeader, Tabs, Markdown, PhoneLink, TabsContent, CardContent, HeaderTabs, usePageTrail, PageHeaderOutlet, ToastProvider, NavTransitionProvider, ListView, Thumbnail, CurrencyInput, TabsList, TabsTrigger, SearchField, ChevronPager, Popover, PopoverTrigger, PopoverContent, useModuleLayout, normalizePhone, SearchCombobox, AppShellSkeleton, usePracticeStore, ViewTabs, setPrintBrand, useModuleViewLabel, ModuleLayoutProvider, AppShell, PageTransition, PickerDialog, MarkdownEditor, PhoneField, isCreateRoute, PageSubNav, MobileScrim, createFayzTheme, PageTrail, Avatar, AvatarImage, AvatarFallback, CardTitle, CardDescription, DropdownSub, DropdownSubTrigger, DropdownSubContent, DropdownRadioGroup, DropdownRadioItem, BottomSheet, SegmentedControl, CardHeader, CardFooter, Separator, SheetCard, SheetRow, useSheetClose } from '@fayz-ai/ui';
@@ -28659,7 +28659,7 @@ function PersonAvailabilityTab({ item }) {
28659
28659
  ] }) });
28660
28660
  }
28661
28661
  var ScheduleEditor2 = React142__default.lazy(
28662
- () => import('./ScheduleEditor-BXWJ7CMI.js').then((m) => ({ default: m.ScheduleEditor }))
28662
+ () => import('./ScheduleEditor-6YFOBHAE.js').then((m) => ({ default: m.ScheduleEditor }))
28663
28663
  );
28664
28664
  var PersonTimeline2 = React142__default.lazy(
28665
28665
  () => import('./PersonTimeline-X7JTPUWJ.js').then((m) => ({ default: m.PersonTimeline }))
@@ -34504,7 +34504,7 @@ var CommandPalette = React142.lazy(
34504
34504
  () => import('./CommandPalette-B5PMQFDG.js').then((m) => ({ default: m.CommandPalette }))
34505
34505
  );
34506
34506
  var SubscriptionPage = React142.lazy(
34507
- () => import('./SubscriptionPage-VBDDRSVW.js').then((m) => ({ default: m.SubscriptionPage }))
34507
+ () => import('./SubscriptionPage-DI6UV5LF.js').then((m) => ({ default: m.SubscriptionPage }))
34508
34508
  );
34509
34509
  function WorkspaceSwitcher({
34510
34510
  variant = "sidebar",
@@ -36316,6 +36316,7 @@ function AdminProviders({ config, children }) {
36316
36316
  if (config.supabaseUrl && config.supabaseAnonKey) {
36317
36317
  createFayzSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);
36318
36318
  }
36319
+ void setServiceUrl(config.serviceUrl);
36319
36320
  const i18n = buildI18nConfig(config);
36320
36321
  setCurrentLocale(resolveLocale(readPersistedLocale(), i18n.supported, i18n.defaultLocale));
36321
36322
  useLocaleStore.getState().hydrateDefault(i18n.defaultLocale);