@fayz-ai/admin 0.62.0 → 0.65.2

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 (171) hide show
  1. package/dist/{CommandPalette-B5PMQFDG.js → CommandPalette-XDJJ5E3O.js} +3 -3
  2. package/dist/{CommandPalette-B5PMQFDG.js.map → CommandPalette-XDJJ5E3O.js.map} +1 -1
  3. package/dist/ConnectedBrandingSettings-43ZM3HCI.js +680 -0
  4. package/dist/ConnectedBrandingSettings-43ZM3HCI.js.map +1 -0
  5. package/dist/ConnectedCompanySettings-I4MALI2Q.js +197 -0
  6. package/dist/ConnectedCompanySettings-I4MALI2Q.js.map +1 -0
  7. package/dist/ConnectedModulesSettings-A2VJ5BMJ.js +563 -0
  8. package/dist/ConnectedModulesSettings-A2VJ5BMJ.js.map +1 -0
  9. package/dist/ConnectedSecuritySettings-25AHA4HJ.js +189 -0
  10. package/dist/ConnectedSecuritySettings-25AHA4HJ.js.map +1 -0
  11. package/dist/ConnectedUserProfile-E7USJRUE.js +424 -0
  12. package/dist/ConnectedUserProfile-E7USJRUE.js.map +1 -0
  13. package/dist/FieldRulesEditor-YGIPKI5T.js +129 -0
  14. package/dist/FieldRulesEditor-YGIPKI5T.js.map +1 -0
  15. package/dist/GettingStartedWidget-HMIJ3Y24.js +12 -0
  16. package/dist/GettingStartedWidget-HMIJ3Y24.js.map +1 -0
  17. package/dist/PermissionProfilesTab-3ZPRCHMZ.js +548 -0
  18. package/dist/PermissionProfilesTab-3ZPRCHMZ.js.map +1 -0
  19. package/dist/PersonTimeline-HQZT527S.js +3 -0
  20. package/dist/{PersonTimeline-X7JTPUWJ.js.map → PersonTimeline-HQZT527S.js.map} +1 -1
  21. package/dist/ProjectsSettings-7O2F27MD.js +5 -0
  22. package/dist/ProjectsSettings-7O2F27MD.js.map +1 -0
  23. package/dist/ScheduleEditor-54ELWR45.js +8 -0
  24. package/dist/{ScheduleEditor-L2UJXKMY.js.map → ScheduleEditor-54ELWR45.js.map} +1 -1
  25. package/dist/SeuSiteWidget-QLSUVC63.js +6 -0
  26. package/dist/SeuSiteWidget-QLSUVC63.js.map +1 -0
  27. package/dist/SubscriptionPage-5GE5HFJK.js +17 -0
  28. package/dist/{SubscriptionPage-IDVEFLZ5.js.map → SubscriptionPage-5GE5HFJK.js.map} +1 -1
  29. package/dist/TeamTab-6RAULFLW.js +502 -0
  30. package/dist/TeamTab-6RAULFLW.js.map +1 -0
  31. package/dist/TrialWidget-Z6CLUCU3.js +7 -0
  32. package/dist/TrialWidget-Z6CLUCU3.js.map +1 -0
  33. package/dist/app/AdminShell.d.ts.map +1 -1
  34. package/dist/app/admin-app.d.ts.map +1 -1
  35. package/dist/app/config.d.ts +14 -0
  36. package/dist/app/config.d.ts.map +1 -1
  37. package/dist/app/routing.d.ts +6 -0
  38. package/dist/app/routing.d.ts.map +1 -1
  39. package/dist/app/scaffold.d.ts.map +1 -1
  40. package/dist/billing/index.js +9 -4
  41. package/dist/chunk-2H46WDG5.js +53 -0
  42. package/dist/chunk-2H46WDG5.js.map +1 -0
  43. package/dist/chunk-3HLX7YB2.js +94 -0
  44. package/dist/chunk-3HLX7YB2.js.map +1 -0
  45. package/dist/chunk-3OUD4XBK.js +3 -0
  46. package/dist/chunk-3OUD4XBK.js.map +1 -0
  47. package/dist/{chunk-IXSY4GPK.js → chunk-5D5QLMOQ.js} +5 -3
  48. package/dist/chunk-5D5QLMOQ.js.map +1 -0
  49. package/dist/chunk-5WR62X2R.js +1081 -0
  50. package/dist/chunk-5WR62X2R.js.map +1 -0
  51. package/dist/{chunk-KPYRTOCK.js → chunk-6CQFGMEO.js} +4 -140
  52. package/dist/chunk-6CQFGMEO.js.map +1 -0
  53. package/dist/chunk-6MMSYC2I.js +116 -0
  54. package/dist/chunk-6MMSYC2I.js.map +1 -0
  55. package/dist/chunk-6QFOE3UD.js +1466 -0
  56. package/dist/chunk-6QFOE3UD.js.map +1 -0
  57. package/dist/chunk-6UUFVQ2E.js +283 -0
  58. package/dist/chunk-6UUFVQ2E.js.map +1 -0
  59. package/dist/chunk-7WNLL3F6.js +7889 -0
  60. package/dist/chunk-7WNLL3F6.js.map +1 -0
  61. package/dist/chunk-A74IHAQE.js +439 -0
  62. package/dist/chunk-A74IHAQE.js.map +1 -0
  63. package/dist/{chunk-JOBRLBIQ.js → chunk-AFA6IO23.js} +4 -3
  64. package/dist/chunk-AFA6IO23.js.map +1 -0
  65. package/dist/{chunk-P5UIGQFY.js → chunk-ALCSIN3Z.js} +5 -5
  66. package/dist/chunk-ALCSIN3Z.js.map +1 -0
  67. package/dist/chunk-AWM4AMBS.js +39 -0
  68. package/dist/chunk-AWM4AMBS.js.map +1 -0
  69. package/dist/{chunk-OQARLKZN.js → chunk-BG5Z6KLN.js} +6 -18
  70. package/dist/chunk-BG5Z6KLN.js.map +1 -0
  71. package/dist/chunk-DPNFZONC.js +19 -0
  72. package/dist/chunk-DPNFZONC.js.map +1 -0
  73. package/dist/chunk-DRCV643L.js +193 -0
  74. package/dist/chunk-DRCV643L.js.map +1 -0
  75. package/dist/chunk-E6DF3VR6.js +206 -0
  76. package/dist/chunk-E6DF3VR6.js.map +1 -0
  77. package/dist/chunk-ENHCVGXZ.js +120 -0
  78. package/dist/chunk-ENHCVGXZ.js.map +1 -0
  79. package/dist/chunk-FK6RHGI7.js +56 -0
  80. package/dist/chunk-FK6RHGI7.js.map +1 -0
  81. package/dist/chunk-G5HNA5QK.js +233 -0
  82. package/dist/chunk-G5HNA5QK.js.map +1 -0
  83. package/dist/chunk-HCFO4Z6A.js +53 -0
  84. package/dist/chunk-HCFO4Z6A.js.map +1 -0
  85. package/dist/chunk-JFIU6NQP.js +51 -0
  86. package/dist/chunk-JFIU6NQP.js.map +1 -0
  87. package/dist/chunk-JRZJBMOY.js +3 -0
  88. package/dist/chunk-JRZJBMOY.js.map +1 -0
  89. package/dist/{chunk-3YP7KW47.js → chunk-JVVOL4BB.js} +41 -512
  90. package/dist/chunk-JVVOL4BB.js.map +1 -0
  91. package/dist/chunk-KAQ3UIAA.js +415 -0
  92. package/dist/chunk-KAQ3UIAA.js.map +1 -0
  93. package/dist/{chunk-P6XUDT2P.js → chunk-KJELMULA.js} +4 -51
  94. package/dist/chunk-KJELMULA.js.map +1 -0
  95. package/dist/chunk-KLO7DKXX.js +1651 -0
  96. package/dist/chunk-KLO7DKXX.js.map +1 -0
  97. package/dist/chunk-M2CMDWUI.js +75 -0
  98. package/dist/chunk-M2CMDWUI.js.map +1 -0
  99. package/dist/chunk-PQ47MLTH.js +255 -0
  100. package/dist/chunk-PQ47MLTH.js.map +1 -0
  101. package/dist/{chunk-VX3WJLKK.js → chunk-QD7BMUDF.js} +17 -8
  102. package/dist/chunk-QD7BMUDF.js.map +1 -0
  103. package/dist/{chunk-E4MESMNR.js → chunk-QTSKCPSW.js} +7 -10
  104. package/dist/chunk-QTSKCPSW.js.map +1 -0
  105. package/dist/chunk-S56FQKPL.js +186 -0
  106. package/dist/chunk-S56FQKPL.js.map +1 -0
  107. package/dist/chunk-SGAFPNMA.js +75 -0
  108. package/dist/chunk-SGAFPNMA.js.map +1 -0
  109. package/dist/{chunk-OD7P4L3D.js → chunk-SOKCLVM4.js} +3 -3
  110. package/dist/{chunk-OD7P4L3D.js.map → chunk-SOKCLVM4.js.map} +1 -1
  111. package/dist/chunk-TL42NKTH.js +3 -0
  112. package/dist/chunk-TL42NKTH.js.map +1 -0
  113. package/dist/chunk-U6ZCO2PS.js +2964 -0
  114. package/dist/chunk-U6ZCO2PS.js.map +1 -0
  115. package/dist/chunk-VSXNROYH.js +16 -0
  116. package/dist/chunk-VSXNROYH.js.map +1 -0
  117. package/dist/chunk-WPFZCYZL.js +619 -0
  118. package/dist/chunk-WPFZCYZL.js.map +1 -0
  119. package/dist/chunk-XFTNIBDW.js +23 -0
  120. package/dist/chunk-XFTNIBDW.js.map +1 -0
  121. package/dist/chunk-Y66JDL6I.js +1020 -0
  122. package/dist/chunk-Y66JDL6I.js.map +1 -0
  123. package/dist/chunk-YEHIBPIX.js +137 -0
  124. package/dist/chunk-YEHIBPIX.js.map +1 -0
  125. package/dist/chunk-YKPPCV2Z.js +53 -0
  126. package/dist/chunk-YKPPCV2Z.js.map +1 -0
  127. package/dist/components/chat/markdown.d.ts.map +1 -1
  128. package/dist/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
  129. package/dist/components/settings/SettingsPage.d.ts.map +1 -1
  130. package/dist/connect-XKQJOWR7.js +18 -0
  131. package/dist/connect-XKQJOWR7.js.map +1 -0
  132. package/dist/crud/CrudDetailPage.d.ts.map +1 -1
  133. package/dist/crud/CrudListView.d.ts.map +1 -1
  134. package/dist/crud/CrudPage.d.ts.map +1 -1
  135. package/dist/crud/RelatedListTab.d.ts.map +1 -1
  136. package/dist/crud/archetypes/EntityLink.d.ts +1 -1
  137. package/dist/crud/archetypes/EntityLink.d.ts.map +1 -1
  138. package/dist/crud/record-chrome.d.ts.map +1 -1
  139. package/dist/entity-routes-PGU7EHAD.js +4 -0
  140. package/dist/{entity-routes-LXOBW5IB.js.map → entity-routes-PGU7EHAD.js.map} +1 -1
  141. package/dist/hooks/useModuleNavigation.d.ts.map +1 -1
  142. package/dist/impersonation/ImpersonateDialog.d.ts.map +1 -1
  143. package/dist/impersonation/session.d.ts.map +1 -1
  144. package/dist/index.d.ts +2 -2
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/index.js +11951 -33576
  147. package/dist/index.js.map +1 -1
  148. package/dist/lib/attention.d.ts +6 -0
  149. package/dist/lib/attention.d.ts.map +1 -1
  150. package/dist/lib/entity-routes.d.ts.map +1 -1
  151. package/dist/org/index.js +4 -2
  152. package/dist/plugins/PluginRegistryManager.d.ts.map +1 -1
  153. package/dist/settings/MessageTemplateRow.d.ts.map +1 -1
  154. package/dist/timeline/PersonTimeline.d.ts.map +1 -1
  155. package/dist/timeline/TimelineList.d.ts.map +1 -1
  156. package/dist/units/UnitRailPage.d.ts.map +1 -1
  157. package/dist/units/useUnitFilter.d.ts.map +1 -1
  158. package/package.json +5 -5
  159. package/dist/PersonTimeline-X7JTPUWJ.js +0 -3
  160. package/dist/ScheduleEditor-L2UJXKMY.js +0 -6
  161. package/dist/SubscriptionPage-IDVEFLZ5.js +0 -8
  162. package/dist/chunk-3YP7KW47.js.map +0 -1
  163. package/dist/chunk-E4MESMNR.js.map +0 -1
  164. package/dist/chunk-IXSY4GPK.js.map +0 -1
  165. package/dist/chunk-JOBRLBIQ.js.map +0 -1
  166. package/dist/chunk-KPYRTOCK.js.map +0 -1
  167. package/dist/chunk-OQARLKZN.js.map +0 -1
  168. package/dist/chunk-P5UIGQFY.js.map +0 -1
  169. package/dist/chunk-P6XUDT2P.js.map +0 -1
  170. package/dist/chunk-VX3WJLKK.js.map +0 -1
  171. package/dist/entity-routes-LXOBW5IB.js +0 -4
@@ -0,0 +1,415 @@
1
+ import { useSettingsUnitScope, UnitScopePicker } from './chunk-2H46WDG5.js';
2
+ import { PendingSettingBadge, SettingsGroup, SelectRow, ToggleRow, TextRow } from './chunk-ENHCVGXZ.js';
3
+ import { useOrganizationStore } from './chunk-YKPPCV2Z.js';
4
+ import * as React from 'react';
5
+ import { getSupabaseClientOptional, usePluginRuntimeOptional, loadMessageOverrides, resolveMessage, tl, navigateApp } from '@fayz-ai/core';
6
+ import { MessageSquareText, Pencil } from 'lucide-react';
7
+ import { Badge, Button, usePublishPageInfo, cn, getLucideIcon } from '@fayz-ai/ui';
8
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
9
+ import { create } from 'zustand';
10
+
11
+ var DEBOUNCE_MS = 400;
12
+ function message(e) {
13
+ if (e instanceof Error) return e.message;
14
+ if (typeof e === "object" && e && "message" in e) return String(e.message);
15
+ return String(e);
16
+ }
17
+ function pick(all, keys) {
18
+ const out = {};
19
+ for (const key of keys) if (key in all) out[key] = all[key];
20
+ return out;
21
+ }
22
+ var same = (a, b) => JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
23
+ var writes = new EventTarget();
24
+ function announce(detail) {
25
+ writes.dispatchEvent(new CustomEvent("write", { detail }));
26
+ }
27
+ function useSettingKeys(keys, unitId = null) {
28
+ const client = React.useMemo(() => getSupabaseClientOptional(), []);
29
+ const supported = !!client;
30
+ const keyList = keys.join("|");
31
+ const [house, setHouse] = React.useState({});
32
+ const [values, setValues] = React.useState({});
33
+ const [loading, setLoading] = React.useState(supported);
34
+ const [saving, setSaving] = React.useState(false);
35
+ const [error, setError] = React.useState(null);
36
+ const [loadError, setLoadError] = React.useState(null);
37
+ React.useEffect(() => {
38
+ if (!client) return;
39
+ let cancelled = false;
40
+ setLoading(true);
41
+ setLoadError(null);
42
+ const reads = [client.rpc("tenant_settings")];
43
+ if (unitId) reads.push(client.rpc("unit_settings", { p_unit: unitId }));
44
+ void Promise.all(reads).then((results) => {
45
+ if (cancelled) return;
46
+ const failed = results.find((r) => r.error);
47
+ if (failed) {
48
+ setLoadError(message(failed.error));
49
+ return;
50
+ }
51
+ const houseValues = pick(results[0].data ?? {}, keys);
52
+ setHouse(houseValues);
53
+ setValues(unitId ? pick(results[1].data ?? {}, keys) : houseValues);
54
+ }).catch((e) => {
55
+ if (!cancelled) setLoadError(message(e));
56
+ }).finally(() => {
57
+ if (!cancelled) setLoading(false);
58
+ });
59
+ return () => {
60
+ cancelled = true;
61
+ };
62
+ }, [client, keyList, unitId]);
63
+ React.useEffect(() => {
64
+ const listener = (event) => {
65
+ const { key, value, unitId: at } = event.detail;
66
+ if (at !== unitId || !keyList.split("|").includes(key)) return;
67
+ setValues((cur) => same(cur[key], value) ? cur : { ...cur, [key]: value });
68
+ if (!unitId) setHouse((cur) => same(cur[key], value) ? cur : { ...cur, [key]: value });
69
+ };
70
+ writes.addEventListener("write", listener);
71
+ return () => writes.removeEventListener("write", listener);
72
+ }, [keyList, unitId]);
73
+ const pendingRef = React.useRef({});
74
+ const timerRef = React.useRef(null);
75
+ React.useEffect(() => () => {
76
+ if (timerRef.current) clearTimeout(timerRef.current);
77
+ }, []);
78
+ const write = React.useCallback((key, value) => {
79
+ if (!client) return;
80
+ setError(null);
81
+ setSaving(true);
82
+ pendingRef.current = { ...pendingRef.current, [key]: value };
83
+ if (timerRef.current) clearTimeout(timerRef.current);
84
+ timerRef.current = setTimeout(() => {
85
+ const payload = pendingRef.current;
86
+ pendingRef.current = {};
87
+ void Promise.all(
88
+ Object.entries(payload).map(
89
+ ([k, v]) => (unitId ? client.rpc("unit_setting_set", { p_key: k, p_value: v ?? null, p_unit: unitId }) : client.rpc("tenant_setting_set", { p_key: k, p_value: v ?? null })).then(({ data, error: e }) => {
90
+ if (e) throw e;
91
+ setValues((cur) => ({ ...cur, [k]: data }));
92
+ if (!unitId) setHouse((cur) => ({ ...cur, [k]: data }));
93
+ announce({ key: k, value: data, unitId });
94
+ })
95
+ )
96
+ ).catch((e) => setError(message(e))).finally(() => setSaving(false));
97
+ }, DEBOUNCE_MS);
98
+ }, [client, unitId]);
99
+ const set = React.useCallback((key, value) => {
100
+ setValues((cur) => ({ ...cur, [key]: value }));
101
+ if (!unitId) setHouse((cur) => ({ ...cur, [key]: value }));
102
+ announce({ key, value, unitId });
103
+ write(key, value);
104
+ }, [write, unitId]);
105
+ const reset = React.useCallback((key) => {
106
+ if (!unitId) return;
107
+ setValues((cur) => ({ ...cur, [key]: house[key] }));
108
+ write(key, null);
109
+ }, [write, unitId, house]);
110
+ const isOverridden = React.useCallback(
111
+ (key) => !!unitId && !same(values[key], house[key]),
112
+ [unitId, values, house]
113
+ );
114
+ return { values, house, isOverridden, set, reset, loading, saving, error, loadError, supported };
115
+ }
116
+ var CHANNEL_LABEL = { whatsapp: "WhatsApp", email: "E-mail", sms: "SMS", push: "Push", webchat: "Chat" };
117
+ function MessageTemplateRow({ label, eventKey, channel = "whatsapp", pending }) {
118
+ const runtime = usePluginRuntimeOptional();
119
+ const tenantId = useOrganizationStore((s) => s.currentOrg?.id);
120
+ const [message2, setMessage] = React.useState(void 0);
121
+ React.useEffect(() => {
122
+ let alive = true;
123
+ loadMessageOverrides(tenantId).then((overrides) => {
124
+ if (alive) setMessage(resolveMessage(eventKey, channel, overrides, runtime?.events ?? []));
125
+ });
126
+ return () => {
127
+ alive = false;
128
+ };
129
+ }, [tenantId, eventKey, channel, runtime?.events]);
130
+ const edit = () => {
131
+ navigateApp(`/automations/${eventKey}/${channel}`);
132
+ };
133
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 py-3", children: [
134
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1", children: [
135
+ /* @__PURE__ */ jsxs("p", { className: "text-sm font-medium", children: [
136
+ label,
137
+ pending && /* @__PURE__ */ jsx(PendingSettingBadge, {})
138
+ ] }),
139
+ message2 === void 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tl("Loading\u2026", "Carregando\u2026") }) : message2 === null ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tl("This message is not in the catalog of this app.", "Esta mensagem n\xE3o est\xE1 no cat\xE1logo deste app.") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
140
+ /* @__PURE__ */ jsx("p", { className: "line-clamp-2 whitespace-pre-line text-xs text-muted-foreground", children: message2.body }),
141
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
142
+ /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "gap-1 font-normal", children: [
143
+ /* @__PURE__ */ jsx(MessageSquareText, { className: "h-3 w-3", "aria-hidden": true }),
144
+ CHANNEL_LABEL[channel] ?? channel
145
+ ] }),
146
+ /* @__PURE__ */ jsx(Badge, { variant: message2.enabled ? "default" : "secondary", className: "font-normal", children: message2.enabled ? tl("On", "Ligada") : tl("Off", "Desligada") }),
147
+ message2.customized && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "font-normal", children: tl("Customised", "Personalizada") })
148
+ ] })
149
+ ] })
150
+ ] }),
151
+ message2 && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "h-9 shrink-0", onClick: edit, children: [
152
+ /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5", "aria-hidden": true }),
153
+ tl("Edit message", "Editar mensagem")
154
+ ] })
155
+ ] });
156
+ }
157
+ function SettingsForm({ description, sections, defaults = {}, pending: pendingForm, comingSoon }) {
158
+ const formPending = pendingForm ?? comingSoon ?? false;
159
+ const hasUnitFields = sections.some((sec) => sec.fields.some((f) => f.scope === "unit"));
160
+ const scope = useSettingsUnitScope();
161
+ const showScope = hasUnitFields && scope.available;
162
+ const unitId = showScope ? scope.unitId : null;
163
+ usePublishPageInfo(description ?? sections.find((sec) => !sec.title && sec.description)?.description);
164
+ const keys = React.useMemo(() => sections.flatMap((sec) => sec.fields.filter((f) => f.type !== "message").map((f) => f.key)), [sections]);
165
+ const s = useSettingKeys(keys, unitId);
166
+ const readOnly = !s.supported;
167
+ const valueOf = (key) => s.values[key] ?? defaults[key];
168
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
169
+ showScope && /* @__PURE__ */ jsx(UnitScopePicker, {}),
170
+ s.loadError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: tl("Could not read the saved settings; showing defaults.", "N\xE3o foi poss\xEDvel ler as configura\xE7\xF5es salvas; mostrando os padr\xF5es.") }),
171
+ s.error && /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
172
+ tl("Not saved", "N\xE3o salvou"),
173
+ ": ",
174
+ s.error
175
+ ] }),
176
+ sections.map((section, i) => {
177
+ const master = sectionMasterKey(section);
178
+ const sectionOff = !!master && valueOf(master) === false;
179
+ return /* @__PURE__ */ jsx(SettingsGroup, { title: section.title, description: section.title ? section.description : void 0, children: section.fields.map((field) => {
180
+ const locked = readOnly || !!unitId && field.scope !== "unit";
181
+ const inherited = !!unitId && field.scope === "unit" && !s.isOverridden(field.key);
182
+ const note = !unitId ? showScope && field.scope === "unit" ? tl("Each unit may differ", "Cada unidade pode ter o seu") : void 0 : field.scope !== "unit" ? tl("Same for the whole network", "Vale para toda a rede") : inherited ? tl("Inherited from the network", "Herdado da rede") : void 0;
183
+ const description2 = [field.description, note].filter(Boolean).join(" \xB7 ") || void 0;
184
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2 transition-opacity", inherited && "opacity-80", sectionOff && field.key !== master && "opacity-50"), children: [
185
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: renderField(field, valueOf(field.key), description2, locked, (v) => s.set(field.key, v), field.pending ?? formPending) }),
186
+ !!unitId && field.scope === "unit" && !inherited && !readOnly && /* @__PURE__ */ jsx(
187
+ Button,
188
+ {
189
+ variant: "bare",
190
+ size: "bare",
191
+ type: "button",
192
+ className: "font-normal whitespace-normal shrink-0 text-xs text-muted-foreground underline-offset-2 hover:underline",
193
+ onClick: () => s.reset(field.key),
194
+ children: tl("Use network value", "Usar o da rede")
195
+ }
196
+ )
197
+ ] }, field.key);
198
+ }) }, section.title ?? i);
199
+ })
200
+ ] });
201
+ }
202
+ function sectionMasterKey(section) {
203
+ if (section.enabledBy === false) return null;
204
+ if (section.enabledBy) return section.enabledBy;
205
+ const first = section.fields.find((f) => f.type === "boolean" && /(\.enabled|\.active|_enabled)$/.test(f.key));
206
+ return first && section.fields.length > 1 ? first.key : null;
207
+ }
208
+ function renderField(field, value, description, disabled, onChange, pending) {
209
+ switch (field.type) {
210
+ case "message":
211
+ return field.message ? /* @__PURE__ */ jsx(MessageTemplateRow, { label: field.label, eventKey: field.message.eventKey, channel: field.message.channel, pending }) : null;
212
+ case "boolean":
213
+ return /* @__PURE__ */ jsx(ToggleRow, { label: field.label, description, checked: value === true, onChange, disabled, pending });
214
+ case "select":
215
+ return /* @__PURE__ */ jsx(
216
+ SelectRow,
217
+ {
218
+ pending,
219
+ label: field.label,
220
+ description,
221
+ value: value == null ? "" : String(value),
222
+ options: field.options ?? [],
223
+ onChange,
224
+ disabled
225
+ }
226
+ );
227
+ case "number":
228
+ return /* @__PURE__ */ jsx(NumberField, { field, value, description, disabled, onChange, pending });
229
+ case "string":
230
+ return /* @__PURE__ */ jsx(StringField, { field, value, description, disabled, onChange, pending });
231
+ }
232
+ }
233
+ function NumberField({ field, value, description, disabled, onChange, pending }) {
234
+ const [draft, setDraft] = React.useState(value == null ? "" : String(value));
235
+ React.useEffect(() => {
236
+ setDraft(value == null ? "" : String(value));
237
+ }, [value]);
238
+ const parsed = draft.trim() === "" ? null : Number(draft.replace(",", "."));
239
+ const invalid = parsed !== null && (!Number.isFinite(parsed) || field.min !== void 0 && parsed < field.min || field.max !== void 0 && parsed > field.max);
240
+ return /* @__PURE__ */ jsx(
241
+ TextRow,
242
+ {
243
+ pending,
244
+ label: field.label,
245
+ description,
246
+ value: draft,
247
+ onChange: setDraft,
248
+ onBlurCommit: () => {
249
+ if (!invalid && parsed !== value) onChange(parsed);
250
+ },
251
+ placeholder: field.placeholder,
252
+ invalid,
253
+ hint: invalid && field.min !== void 0 && field.max !== void 0 ? `${field.min}\u2013${field.max}` : void 0,
254
+ disabled
255
+ }
256
+ );
257
+ }
258
+ function StringField({ field, value, description, disabled, onChange, pending }) {
259
+ const [draft, setDraft] = React.useState(value == null ? "" : String(value));
260
+ React.useEffect(() => {
261
+ setDraft(value == null ? "" : String(value));
262
+ }, [value]);
263
+ return /* @__PURE__ */ jsx(
264
+ TextRow,
265
+ {
266
+ pending,
267
+ label: field.label,
268
+ description,
269
+ value: draft,
270
+ onChange: setDraft,
271
+ onBlurCommit: () => {
272
+ const next = draft.trim() === "" ? null : draft;
273
+ if (next !== value) onChange(next);
274
+ },
275
+ placeholder: field.placeholder,
276
+ disabled
277
+ }
278
+ );
279
+ }
280
+ function tab(id, label, iconName, section, form) {
281
+ const Icon = getLucideIcon(iconName);
282
+ return {
283
+ id,
284
+ label,
285
+ iconName,
286
+ icon: Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }) : void 0,
287
+ section,
288
+ component: /* @__PURE__ */ jsx(SettingsForm, { ...form })
289
+ };
290
+ }
291
+ function CompanyTypeSettings() {
292
+ return /* @__PURE__ */ jsx(
293
+ SettingsForm,
294
+ {
295
+ pending: true,
296
+ defaults: { "company.type": "multi" },
297
+ sections: [{
298
+ title: tl("Company type", "Tipo de empresa"),
299
+ description: tl(
300
+ "In franchise mode head office sees the whole network and edits the shared catalog; each franchisee sees only its own.",
301
+ "Em franquia, a franqueadora v\xEA a rede toda e edita o cat\xE1logo comum; cada franqueado v\xEA s\xF3 o que \xE9 dele."
302
+ ),
303
+ fields: [{ key: "company.type", type: "select", label: tl("This account is", "Esta conta \xE9"), options: [
304
+ { value: "multi", label: tl("Multi-company", "Multiempresa") },
305
+ { value: "franchise", label: tl("Franchise", "Franquia") }
306
+ ] }]
307
+ }]
308
+ }
309
+ );
310
+ }
311
+ function coreV1SettingsTabs() {
312
+ return [
313
+ {
314
+ // The account's access layers in one screen; "Acesso via QR Code" was its
315
+ // own line and is now the first layer here (old link redirects).
316
+ ...tab("access", tl("Access methods", "M\xE9todos de acesso"), "Lock", "security", {
317
+ pending: true,
318
+ description: tl(
319
+ "Who may enter the account and how: the layers on top of the password.",
320
+ "Quem entra na conta e como: as camadas por cima da senha."
321
+ ),
322
+ defaults: {
323
+ "qr_access.enabled": false,
324
+ "qr_access.hours_valid": 12,
325
+ "qr_access.scan_window_minutes": 5,
326
+ "access.require_2fa": false,
327
+ "access.invite_only": true,
328
+ "access.session_timeout_minutes": 0
329
+ },
330
+ sections: [
331
+ {
332
+ title: tl("QR code access", "Acesso via QR Code"),
333
+ description: tl("People enter only after scanning a QR code generated in the unit.", "A pessoa s\xF3 entra no sistema depois de ler um QR Code gerado na unidade."),
334
+ fields: [
335
+ { key: "qr_access.enabled", type: "boolean", label: tl("Require QR access", "Ativar camada de prote\xE7\xE3o") },
336
+ { key: "qr_access.hours_valid", type: "number", min: 1, max: 72, label: tl("Access lasts (hours)", "Acesso vale por (horas)") },
337
+ { key: "qr_access.scan_window_minutes", type: "number", min: 1, max: 60, label: tl("QR code valid for (minutes)", "QR Code vale por (minutos)") }
338
+ ]
339
+ },
340
+ {
341
+ title: tl("Two-factor authentication (2FA)", "Autentica\xE7\xE3o em dois fatores (2FA)"),
342
+ description: tl("Every login confirms with a code from an authenticator app.", "Cada login confirma com um c\xF3digo de um app autenticador."),
343
+ fields: [
344
+ { key: "access.require_2fa", type: "boolean", label: tl("Require 2FA for everyone", "Exigir 2FA de todos") }
345
+ ]
346
+ },
347
+ {
348
+ title: tl("Sessions and invitations", "Sess\xF5es e convites"),
349
+ fields: [
350
+ { key: "access.invite_only", type: "boolean", label: tl("Only invited people join", "S\xF3 entra quem foi convidado") },
351
+ {
352
+ key: "access.session_timeout_minutes",
353
+ type: "number",
354
+ min: 0,
355
+ max: 1440,
356
+ label: tl("Sign out after inactivity (minutes, 0 = no limit)", "Sair por inatividade ap\xF3s (minutos, 0 = sem limite)")
357
+ }
358
+ ]
359
+ }
360
+ ]
361
+ }),
362
+ children: [{ id: "qr-access", label: tl("QR code access", "Acesso via QR Code"), href: "/settings/access" }]
363
+ },
364
+ tab("assistant", tl("Support assistant", "Assistente de suporte"), "WandSparkles", "communication", {
365
+ pending: true,
366
+ defaults: { "assistant.enabled": true, "assistant.write_actions": true, "assistant.destructive_actions": false, "assistant.turns_per_user_hour": 60, "assistant.retention_days": 180 },
367
+ sections: [{
368
+ description: tl("The assistant proposes, the person confirms; screen permissions still apply.", "O assistente prop\xF5e e a pessoa confirma; as permiss\xF5es de tela continuam valendo."),
369
+ fields: [
370
+ { key: "assistant.enabled", type: "boolean", label: tl("Assistant on", "Assistente ativo") },
371
+ { key: "assistant.write_actions", type: "boolean", label: tl("May create and edit records", "Pode criar e alterar registros") },
372
+ { key: "assistant.destructive_actions", type: "boolean", label: tl("May delete and cancel", "Pode excluir e cancelar") },
373
+ { key: "assistant.turns_per_user_hour", type: "number", min: 1, max: 1e3, label: tl("Messages per person per hour", "Mensagens por pessoa por hora") },
374
+ { key: "assistant.retention_days", type: "number", min: 7, max: 3650, label: tl("Keep conversations for (days)", "Guardar conversas por (dias)") },
375
+ { key: "assistant.custom_instructions", type: "string", label: tl("Extra instructions", "Instru\xE7\xF5es adicionais") }
376
+ ]
377
+ }]
378
+ })
379
+ ];
380
+ }
381
+ var STORAGE_KEY = "saas-core:locale";
382
+ function readPersistedLocale() {
383
+ try {
384
+ return localStorage.getItem(STORAGE_KEY) ?? void 0;
385
+ } catch {
386
+ return void 0;
387
+ }
388
+ }
389
+ function getPersistedLocale() {
390
+ return readPersistedLocale() ?? "en";
391
+ }
392
+ var useLocaleStore = create((set) => ({
393
+ locale: getPersistedLocale(),
394
+ setLocale: (locale) => {
395
+ try {
396
+ localStorage.setItem(STORAGE_KEY, locale);
397
+ } catch {
398
+ }
399
+ set({ locale });
400
+ },
401
+ hydrateDefault: (locale) => {
402
+ if (readPersistedLocale()) return;
403
+ set({ locale });
404
+ }
405
+ }));
406
+
407
+ // src/lib/locale-config.ts
408
+ var SUPPORTED_LOCALES = [
409
+ { code: "en", label: "English", flag: "\u{1F1FA}\u{1F1F8}" },
410
+ { code: "pt-BR", label: "Portugu\xEAs (BR)", flag: "\u{1F1E7}\u{1F1F7}" }
411
+ ];
412
+
413
+ export { CompanyTypeSettings, MessageTemplateRow, SUPPORTED_LOCALES, SettingsForm, coreV1SettingsTabs, readPersistedLocale, useLocaleStore, useSettingKeys };
414
+ //# sourceMappingURL=chunk-KAQ3UIAA.js.map
415
+ //# sourceMappingURL=chunk-KAQ3UIAA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/settings/useSettingKeys.ts","../src/settings/MessageTemplateRow.tsx","../src/settings/SettingsForm.tsx","../src/settings/core-v1-tabs.tsx","../src/stores/locale.store.ts","../src/lib/locale-config.ts"],"names":["message","React2","React3","jsxs","jsx","tl","description","Button"],"mappings":"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","file":"chunk-KAQ3UIAA.js","sourcesContent":["import * as React from 'react'\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\n\nconst DEBOUNCE_MS = 400\n\nexport interface SettingKeysHandle {\n /** Effective value per key where the screen stands: the unit when `unitId`\n * is set (unit → house → registry default), else the house. */\n values: Record<string, unknown>\n /** The house value per key, so a unit screen can say \"inherited\". */\n house: Record<string, unknown>\n /** Whether this unit holds its own value for `key`. */\n isOverridden: (key: string) => boolean\n set: (key: string, value: unknown) => void\n /** Drops the unit's own value; the unit goes back to the house default. */\n reset: (key: string) => void\n loading: boolean\n saving: boolean\n /** A write was refused; the optimistic value stays on screen. */\n error: string | null\n /** The read failed: what is on screen are defaults, not the house's choices. */\n loadError: string | null\n /** No backend mounted (mock/standalone). */\n supported: boolean\n}\n\nfunction message(e: unknown): string {\n if (e instanceof Error) return e.message\n if (typeof e === 'object' && e && 'message' in e) return String((e as { message: unknown }).message)\n return String(e)\n}\n\nfunction pick(all: Record<string, unknown>, keys: readonly string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const key of keys) if (key in all) out[key] = all[key]\n return out\n}\n\nconst same = (a: unknown, b: unknown) => JSON.stringify(a ?? null) === JSON.stringify(b ?? null)\n\n/**\n * Every mounted reader of the same key, told about a write.\n *\n * One setting can have two switches on screen at once — the top bar's\n * «Delivery» chip and Configurações › Delivery both write `delivery.enabled` —\n * and each hook instance held its own copy, so flipping one left the other\n * showing the old state. A write is announced here (optimistic, then the\n * value the database resolved) and every instance standing at the same place\n * (same unit, or both on the house) takes it.\n */\ntype SettingWrite = { key: string; value: unknown; unitId: string | null }\nconst writes = new EventTarget()\nfunction announce(detail: SettingWrite): void {\n writes.dispatchEvent(new CustomEvent<SettingWrite>('write', { detail }))\n}\n\n/**\n * Reads and writes registered setting keys (`app.tenant_setting_keys`) through\n * the spine RPCs: `tenant_settings` / `tenant_setting_set` for the house,\n * `unit_settings` / `unit_setting_set` for a unit's own value. The database\n * types, defaults and permission-checks every key; this hook only debounces.\n */\nexport function useSettingKeys(keys: readonly string[], unitId: string | null = null): SettingKeysHandle {\n const client = React.useMemo(() => getSupabaseClientOptional() as any, [])\n const supported = !!client\n const keyList = keys.join('|')\n\n const [house, setHouse] = React.useState<Record<string, unknown>>({})\n const [values, setValues] = React.useState<Record<string, unknown>>({})\n const [loading, setLoading] = React.useState(supported)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [loadError, setLoadError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n if (!client) return\n let cancelled = false\n setLoading(true)\n setLoadError(null)\n const reads = [client.rpc('tenant_settings')]\n if (unitId) reads.push(client.rpc('unit_settings', { p_unit: unitId }))\n void Promise.all(reads)\n .then((results: Array<{ data: Record<string, unknown> | null; error: unknown }>) => {\n if (cancelled) return\n const failed = results.find((r) => r.error)\n if (failed) { setLoadError(message(failed.error)); return }\n const houseValues = pick(results[0].data ?? {}, keys)\n setHouse(houseValues)\n setValues(unitId ? pick(results[1].data ?? {}, keys) : houseValues)\n })\n .catch((e: unknown) => { if (!cancelled) setLoadError(message(e)) })\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n // keyList stands for `keys`: a new array with the same keys is the same read.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, keyList, unitId])\n\n React.useEffect(() => {\n const listener = (event: Event) => {\n const { key, value, unitId: at } = (event as CustomEvent<SettingWrite>).detail\n if (at !== unitId || !keyList.split('|').includes(key)) return\n setValues((cur) => (same(cur[key], value) ? cur : { ...cur, [key]: value }))\n if (!unitId) setHouse((cur) => (same(cur[key], value) ? cur : { ...cur, [key]: value }))\n }\n writes.addEventListener('write', listener)\n return () => writes.removeEventListener('write', listener)\n }, [keyList, unitId])\n\n const pendingRef = React.useRef<Record<string, unknown>>({})\n const timerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n React.useEffect(() => () => { if (timerRef.current) clearTimeout(timerRef.current) }, [])\n\n const write = React.useCallback((key: string, value: unknown) => {\n if (!client) return\n setError(null)\n setSaving(true)\n pendingRef.current = { ...pendingRef.current, [key]: value }\n if (timerRef.current) clearTimeout(timerRef.current)\n timerRef.current = setTimeout(() => {\n const payload = pendingRef.current\n pendingRef.current = {}\n void Promise.all(\n Object.entries(payload).map(([k, v]) =>\n (unitId\n ? client.rpc('unit_setting_set', { p_key: k, p_value: v ?? null, p_unit: unitId })\n : client.rpc('tenant_setting_set', { p_key: k, p_value: v ?? null })\n ).then(({ data, error: e }: { data: unknown; error: unknown }) => {\n if (e) throw e\n // The RPC answers with the resolved value — after a reset that is\n // the house's, which the optimistic `null` could not know.\n setValues((cur) => ({ ...cur, [k]: data }))\n if (!unitId) setHouse((cur) => ({ ...cur, [k]: data }))\n announce({ key: k, value: data, unitId })\n }),\n ),\n )\n .catch((e: unknown) => setError(message(e)))\n .finally(() => setSaving(false))\n }, DEBOUNCE_MS)\n }, [client, unitId])\n\n const set = React.useCallback((key: string, value: unknown) => {\n setValues((cur) => ({ ...cur, [key]: value }))\n if (!unitId) setHouse((cur) => ({ ...cur, [key]: value }))\n announce({ key, value, unitId })\n write(key, value)\n }, [write, unitId])\n\n const reset = React.useCallback((key: string) => {\n if (!unitId) return\n setValues((cur) => ({ ...cur, [key]: house[key] }))\n write(key, null)\n }, [write, unitId, house])\n\n const isOverridden = React.useCallback(\n (key: string) => !!unitId && !same(values[key], house[key]),\n [unitId, values, house],\n )\n\n return { values, house, isOverridden, set, reset, loading, saving, error, loadError, supported }\n}\n","import * as React from 'react'\nimport { MessageSquareText, Pencil } from 'lucide-react'\nimport {\n loadMessageOverrides, resolveMessage, tl, usePluginRuntimeOptional,\n type MessageChannel, type ResolvedMessage,\n navigateApp,\n} from '@fayz-ai/core'\nimport { Badge, Button } from '@fayz-ai/ui'\nimport { useOrganizationStore } from '../stores/organization.store'\nimport { PendingSettingBadge } from '../plugins/SettingsGroup'\n\nconst CHANNEL_LABEL: Record<string, string> = { whatsapp: 'WhatsApp', email: 'E-mail', sms: 'SMS', push: 'Push', webchat: 'Chat' }\n\n/**\n * A setting whose value is a MESSAGE: one record of the shared template\n * catalog (event × channel, customised in Automações › Mensagens), shown here\n * as a preview with a way to edit it. No copy of the text lives in the setting,\n * so the confirmation a screen sends and the one Automações sends are the same.\n */\nexport function MessageTemplateRow({ label, eventKey, channel = 'whatsapp', pending }: {\n label: string\n eventKey: string\n channel?: MessageChannel\n /** Nothing sends this message yet (no emitter for its event). */\n pending?: boolean\n}) {\n const runtime = usePluginRuntimeOptional()\n const tenantId = useOrganizationStore((s) => s.currentOrg?.id)\n const [message, setMessage] = React.useState<ResolvedMessage | null | undefined>(undefined)\n\n React.useEffect(() => {\n let alive = true\n loadMessageOverrides(tenantId).then((overrides) => {\n if (alive) setMessage(resolveMessage(eventKey, channel, overrides, (runtime?.events ?? []) as never))\n })\n return () => { alive = false }\n }, [tenantId, eventKey, channel, runtime?.events])\n\n const edit = () => { navigateApp(`/automations/${eventKey}/${channel}`) }\n\n return (\n <div className=\"flex items-start justify-between gap-4 py-3\">\n <div className=\"min-w-0 space-y-1\">\n <p className=\"text-sm font-medium\">\n {label}\n {pending && <PendingSettingBadge />}\n </p>\n {message === undefined ? (\n <p className=\"text-xs text-muted-foreground\">{tl('Loading…', 'Carregando…')}</p>\n ) : message === null ? (\n <p className=\"text-xs text-muted-foreground\">\n {tl('This message is not in the catalog of this app.', 'Esta mensagem não está no catálogo deste app.')}\n </p>\n ) : (\n <>\n <p className=\"line-clamp-2 whitespace-pre-line text-xs text-muted-foreground\">{message.body}</p>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <Badge variant=\"outline\" className=\"gap-1 font-normal\">\n <MessageSquareText className=\"h-3 w-3\" aria-hidden />{CHANNEL_LABEL[channel] ?? channel}\n </Badge>\n <Badge variant={message.enabled ? 'default' : 'secondary'} className=\"font-normal\">\n {message.enabled ? tl('On', 'Ligada') : tl('Off', 'Desligada')}\n </Badge>\n {message.customized && <Badge variant=\"secondary\" className=\"font-normal\">{tl('Customised', 'Personalizada')}</Badge>}\n </div>\n </>\n )}\n </div>\n {message && (\n <Button variant=\"outline\" size=\"sm\" className=\"h-9 shrink-0\" onClick={edit}>\n <Pencil className=\"h-3.5 w-3.5\" aria-hidden />\n {tl('Edit message', 'Editar mensagem')}\n </Button>\n )}\n </div>\n )\n}\n","import * as React from 'react'\nimport { tl, type MessageChannel } from '@fayz-ai/core'\nimport { Button, cn, usePublishPageInfo } from '@fayz-ai/ui'\nimport { SettingsGroup, ToggleRow, SelectRow, TextRow } from '../plugins/SettingsGroup'\nimport { useSettingKeys } from './useSettingKeys'\nimport { MessageTemplateRow } from './MessageTemplateRow'\nimport { UnitScopePicker, useSettingsUnitScope } from './UnitScopePicker'\n\nexport type SettingFieldType = 'boolean' | 'number' | 'string' | 'select' | 'message'\n\nexport interface SettingField {\n /** A key registered in `app.tenant_setting_keys`. */\n key: string\n label: string\n description?: string\n type: SettingFieldType\n options?: { value: string; label: string }[]\n /** `unit`: each unit may hold its own value over the house default. */\n scope?: 'tenant' | 'unit'\n min?: number\n max?: number\n placeholder?: string\n /** Saves, but no feature reads it yet — shows the \"Em breve\" mark. Defaults\n * to the form's `pending`. */\n pending?: boolean\n /** `type: 'message'`: the shared template this row points at (Automações ›\n * Mensagens). The row stores nothing; `key` only names it. */\n message?: { eventKey: string; channel?: MessageChannel }\n}\n\nexport interface SettingsFormSection {\n title?: string\n description?: string\n /** The boolean key that switches this section on. While it is off, the\n * section's other rows are dimmed (still readable and editable). Inferred\n * from the first boolean key ending in `.enabled` / `.active` / `_enabled`;\n * `false` opts out. */\n enabledBy?: string | false\n fields: SettingField[]\n}\n\nexport interface SettingsFormProps {\n /** What this screen is for, in one sentence — shown as the (i) by the title.\n * Defaults to the first untitled section's description. */\n description?: string\n sections: SettingsFormSection[]\n /** Shown while the house has decided nothing — mirrors the registry default. */\n defaults?: Record<string, unknown>\n /** No feature reads these settings yet: every row saves, and carries the\n * \"Em breve\" mark unless the field says `pending: false`. */\n pending?: boolean\n /** @deprecated Same as `pending`. Screens used to be read-only; they save now. */\n comingSoon?: boolean\n}\n\n/**\n * The standard settings screen: declared fields, saved key by key to the typed\n * registry. When any field may differ per unit, the bar shows the shared\n * \"Configurar para\" picker.\n */\nexport function SettingsForm({ description, sections, defaults = {}, pending: pendingForm, comingSoon }: SettingsFormProps) {\n const formPending = pendingForm ?? comingSoon ?? false\n const hasUnitFields = sections.some((sec) => sec.fields.some((f) => f.scope === 'unit'))\n const scope = useSettingsUnitScope()\n const showScope = hasUnitFields && scope.available\n const unitId = showScope ? scope.unitId : null\n\n usePublishPageInfo(description ?? sections.find((sec) => !sec.title && sec.description)?.description)\n\n const keys = React.useMemo(() => sections.flatMap((sec) => sec.fields.filter((f) => f.type !== 'message').map((f) => f.key)), [sections])\n const s = useSettingKeys(keys, unitId)\n const readOnly = !s.supported\n\n const valueOf = (key: string) => (s.values[key] ?? defaults[key])\n\n return (\n <div className=\"space-y-4\">\n {showScope && <UnitScopePicker />}\n\n {s.loadError && (\n <p className=\"text-sm text-destructive\">\n {tl('Could not read the saved settings; showing defaults.', 'Não foi possível ler as configurações salvas; mostrando os padrões.')}\n </p>\n )}\n {s.error && <p className=\"text-sm text-destructive\">{tl('Not saved', 'Não salvou')}: {s.error}</p>}\n\n {sections.map((section, i) => {\n const master = sectionMasterKey(section)\n const sectionOff = !!master && valueOf(master) === false\n return (\n <SettingsGroup key={section.title ?? i} title={section.title} description={section.title ? section.description : undefined}>\n {section.fields.map((field) => {\n // A house-wide key cannot vary per unit: on a unit, it is shown, not edited.\n const locked = readOnly || (!!unitId && field.scope !== 'unit')\n const inherited = !!unitId && field.scope === 'unit' && !s.isOverridden(field.key)\n const note = !unitId\n ? (showScope && field.scope === 'unit' ? tl('Each unit may differ', 'Cada unidade pode ter o seu') : undefined)\n : field.scope !== 'unit'\n ? tl('Same for the whole network', 'Vale para toda a rede')\n : inherited\n ? tl('Inherited from the network', 'Herdado da rede')\n : undefined\n const description = [field.description, note].filter(Boolean).join(' · ') || undefined\n return (\n <div key={field.key} className={cn('flex items-center gap-2 transition-opacity', inherited && 'opacity-80', sectionOff && field.key !== master && 'opacity-50')}>\n <div className=\"min-w-0 flex-1\">{renderField(field, valueOf(field.key), description, locked, (v) => s.set(field.key, v), field.pending ?? formPending)}</div>\n {!!unitId && field.scope === 'unit' && !inherited && !readOnly && (\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n className=\"font-normal whitespace-normal shrink-0 text-xs text-muted-foreground underline-offset-2 hover:underline\"\n onClick={() => s.reset(field.key)}\n >\n {tl('Use network value', 'Usar o da rede')}\n </Button>\n )}\n </div>\n )\n })}\n </SettingsGroup>\n )\n })}\n </div>\n )\n}\n\n/** The switch that turns a section on, if it has one. */\nexport function sectionMasterKey(section: SettingsFormSection): string | null {\n if (section.enabledBy === false) return null\n if (section.enabledBy) return section.enabledBy\n const first = section.fields.find((f) => f.type === 'boolean' && /(\\.enabled|\\.active|_enabled)$/.test(f.key))\n return first && section.fields.length > 1 ? first.key : null\n}\n\nfunction renderField(\n field: SettingField,\n value: unknown,\n description: string | undefined,\n disabled: boolean,\n onChange: (value: unknown) => void,\n pending: boolean,\n): React.ReactNode {\n switch (field.type) {\n case 'message':\n return field.message\n ? <MessageTemplateRow label={field.label} eventKey={field.message.eventKey} channel={field.message.channel} pending={pending} />\n : null\n case 'boolean':\n return <ToggleRow label={field.label} description={description} checked={value === true} onChange={onChange} disabled={disabled} pending={pending} />\n case 'select':\n return (\n <SelectRow\n pending={pending}\n label={field.label}\n description={description}\n value={value == null ? '' : String(value)}\n options={field.options ?? []}\n onChange={onChange}\n disabled={disabled}\n />\n )\n case 'number':\n return <NumberField field={field} value={value} description={description} disabled={disabled} onChange={onChange} pending={pending} />\n case 'string':\n return <StringField field={field} value={value} description={description} disabled={disabled} onChange={onChange} pending={pending} />\n }\n}\n\nfunction NumberField({ field, value, description, disabled, onChange, pending }: {\n field: SettingField; value: unknown; description?: string; disabled: boolean; onChange: (v: unknown) => void; pending?: boolean\n}) {\n const [draft, setDraft] = React.useState(value == null ? '' : String(value))\n React.useEffect(() => { setDraft(value == null ? '' : String(value)) }, [value])\n const parsed = draft.trim() === '' ? null : Number(draft.replace(',', '.'))\n const invalid = parsed !== null && (!Number.isFinite(parsed)\n || (field.min !== undefined && parsed < field.min)\n || (field.max !== undefined && parsed > field.max))\n return (\n <TextRow\n pending={pending}\n label={field.label}\n description={description}\n value={draft}\n onChange={setDraft}\n onBlurCommit={() => { if (!invalid && parsed !== value) onChange(parsed) }}\n placeholder={field.placeholder}\n invalid={invalid}\n hint={invalid && field.min !== undefined && field.max !== undefined ? `${field.min}–${field.max}` : undefined}\n disabled={disabled}\n />\n )\n}\n\nfunction StringField({ field, value, description, disabled, onChange, pending }: {\n field: SettingField; value: unknown; description?: string; disabled: boolean; onChange: (v: unknown) => void; pending?: boolean\n}) {\n const [draft, setDraft] = React.useState(value == null ? '' : String(value))\n React.useEffect(() => { setDraft(value == null ? '' : String(value)) }, [value])\n return (\n <TextRow\n pending={pending}\n label={field.label}\n description={description}\n value={draft}\n onChange={setDraft}\n onBlurCommit={() => { const next = draft.trim() === '' ? null : draft; if (next !== value) onChange(next) }}\n placeholder={field.placeholder}\n disabled={disabled}\n />\n )\n}\n","import * as React from 'react'\nimport { tl } from '@fayz-ai/core'\nimport { getLucideIcon } from '@fayz-ai/ui'\nimport type { SettingsTab } from '../components/settings/SettingsPage'\nimport { SettingsForm, type SettingsFormProps } from './SettingsForm'\n\nfunction tab(id: string, label: string, iconName: string, section: SettingsTab['section'], form: SettingsFormProps): SettingsTab {\n const Icon = getLucideIcon(iconName)\n return {\n id,\n label,\n iconName,\n icon: Icon ? <Icon className=\"h-4 w-4\" /> : undefined,\n section,\n component: <SettingsForm {...form} />,\n }\n}\n\n/** V1's \"Tipo de empresa\", shown inside Geral next to unit management —\n * the same question about how the business is shaped. */\nexport function CompanyTypeSettings() {\n return (\n <SettingsForm\n pending\n defaults={{ 'company.type': 'multi' }}\n sections={[{\n title: tl('Company type', 'Tipo de empresa'),\n description: tl('In franchise mode head office sees the whole network and edits the shared catalog; each franchisee sees only its own.',\n 'Em franquia, a franqueadora vê a rede toda e edita o catálogo comum; cada franqueado vê só o que é dele.'),\n fields: [{ key: 'company.type', type: 'select', label: tl('This account is', 'Esta conta é'), options: [\n { value: 'multi', label: tl('Multi-company', 'Multiempresa') },\n { value: 'franchise', label: tl('Franchise', 'Franquia') },\n ] }],\n }]}\n />\n )\n}\n\n/** V1 account-level settings the shell owns. They save; rows nothing reads yet are marked. */\nexport function coreV1SettingsTabs(): SettingsTab[] {\n return [\n {\n // The account's access layers in one screen; \"Acesso via QR Code\" was its\n // own line and is now the first layer here (old link redirects).\n ...tab('access', tl('Access methods', 'Métodos de acesso'), 'Lock', 'security', {\n pending: true,\n description: tl('Who may enter the account and how: the layers on top of the password.',\n 'Quem entra na conta e como: as camadas por cima da senha.'),\n defaults: {\n 'qr_access.enabled': false, 'qr_access.hours_valid': 12, 'qr_access.scan_window_minutes': 5,\n 'access.require_2fa': false, 'access.invite_only': true, 'access.session_timeout_minutes': 0,\n },\n sections: [\n {\n title: tl('QR code access', 'Acesso via QR Code'),\n description: tl('People enter only after scanning a QR code generated in the unit.', 'A pessoa só entra no sistema depois de ler um QR Code gerado na unidade.'),\n fields: [\n { key: 'qr_access.enabled', type: 'boolean', label: tl('Require QR access', 'Ativar camada de proteção') },\n { key: 'qr_access.hours_valid', type: 'number', min: 1, max: 72, label: tl('Access lasts (hours)', 'Acesso vale por (horas)') },\n { key: 'qr_access.scan_window_minutes', type: 'number', min: 1, max: 60, label: tl('QR code valid for (minutes)', 'QR Code vale por (minutos)') },\n ],\n },\n {\n title: tl('Two-factor authentication (2FA)', 'Autenticação em dois fatores (2FA)'),\n description: tl('Every login confirms with a code from an authenticator app.', 'Cada login confirma com um código de um app autenticador.'),\n fields: [\n { key: 'access.require_2fa', type: 'boolean', label: tl('Require 2FA for everyone', 'Exigir 2FA de todos') },\n ],\n },\n {\n title: tl('Sessions and invitations', 'Sessões e convites'),\n fields: [\n { key: 'access.invite_only', type: 'boolean', label: tl('Only invited people join', 'Só entra quem foi convidado') },\n { key: 'access.session_timeout_minutes', type: 'number', min: 0, max: 1440,\n label: tl('Sign out after inactivity (minutes, 0 = no limit)', 'Sair por inatividade após (minutos, 0 = sem limite)') },\n ],\n },\n ],\n }),\n children: [{ id: 'qr-access', label: tl('QR code access', 'Acesso via QR Code'), href: '/settings/access' }],\n },\n tab('assistant', tl('Support assistant', 'Assistente de suporte'), 'WandSparkles', 'communication', {\n pending: true,\n defaults: { 'assistant.enabled': true, 'assistant.write_actions': true, 'assistant.destructive_actions': false, 'assistant.turns_per_user_hour': 60, 'assistant.retention_days': 180 },\n sections: [{\n description: tl('The assistant proposes, the person confirms; screen permissions still apply.', 'O assistente propõe e a pessoa confirma; as permissões de tela continuam valendo.'),\n fields: [\n { key: 'assistant.enabled', type: 'boolean', label: tl('Assistant on', 'Assistente ativo') },\n { key: 'assistant.write_actions', type: 'boolean', label: tl('May create and edit records', 'Pode criar e alterar registros') },\n { key: 'assistant.destructive_actions', type: 'boolean', label: tl('May delete and cancel', 'Pode excluir e cancelar') },\n { key: 'assistant.turns_per_user_hour', type: 'number', min: 1, max: 1000, label: tl('Messages per person per hour', 'Mensagens por pessoa por hora') },\n { key: 'assistant.retention_days', type: 'number', min: 7, max: 3650, label: tl('Keep conversations for (days)', 'Guardar conversas por (dias)') },\n { key: 'assistant.custom_instructions', type: 'string', label: tl('Extra instructions', 'Instruções adicionais') },\n ],\n }],\n }),\n ]\n}\n","import { create } from 'zustand'\n\nconst STORAGE_KEY = 'saas-core:locale'\n\n/** The locale the user picked, or undefined on a first visit. */\nexport function readPersistedLocale(): string | undefined {\n try {\n return localStorage.getItem(STORAGE_KEY) ?? undefined\n } catch {\n return undefined\n }\n}\n\nfunction getPersistedLocale(): string {\n return readPersistedLocale() ?? 'en'\n}\n\ninterface LocaleState {\n locale: string\n setLocale: (locale: string) => void\n /**\n * Adopt the app config's default locale on a first visit — WITHOUT persisting\n * it, so the user's own pick is still what gets written later. Without this\n * the store starts at 'en' and a pt-BR app paints its shell in English until\n * someone touches the language switch (which is why every app hand-called\n * `setCurrentLocale` in main.tsx).\n */\n hydrateDefault: (locale: string) => void\n}\n\nexport const useLocaleStore = create<LocaleState>((set) => ({\n locale: getPersistedLocale(),\n setLocale: (locale) => {\n try { localStorage.setItem(STORAGE_KEY, locale) } catch { /* ignore */ }\n set({ locale })\n },\n hydrateDefault: (locale) => {\n if (readPersistedLocale()) return\n set({ locale })\n },\n}))\n","export interface LocaleOption {\n code: string\n label: string\n flag: string\n}\n\nexport const SUPPORTED_LOCALES: LocaleOption[] = [\n { code: 'en', label: 'English', flag: '🇺🇸' },\n { code: 'pt-BR', label: 'Português (BR)', flag: '🇧🇷' },\n]\n\nexport function getLocaleOption(code: string): LocaleOption {\n return SUPPORTED_LOCALES.find((l) => l.code === code) ?? SUPPORTED_LOCALES[0]\n}\n"]}
@@ -1,8 +1,6 @@
1
1
  import { createClient } from '@supabase/supabase-js';
2
- import { setActiveTenantId, getActiveUnitId, getActiveTenantId, setGlobalSupabaseClient, getSupabaseClientOptional as getSupabaseClientOptional$1 } from '@fayz-ai/core';
2
+ import { getActiveUnitId, getActiveTenantId, setGlobalSupabaseClient, getSupabaseClientOptional as getSupabaseClientOptional$1 } from '@fayz-ai/core';
3
3
  import { createDedupedFetch } from '@fayz-ai/sdk';
4
- import { create } from 'zustand';
5
- export { cn } from '@fayz-ai/ui';
6
4
 
7
5
  // src/data/client.ts
8
6
  var _client = null;
@@ -96,53 +94,8 @@ function getFayzSupabaseClient() {
96
94
  function getFayzSupabaseClientOptional() {
97
95
  return _client;
98
96
  }
99
- var STORAGE_KEY = "fayz:current-org";
100
- function getPersistedOrgId() {
101
- try {
102
- if (typeof localStorage === "undefined") return null;
103
- return localStorage.getItem(STORAGE_KEY);
104
- } catch {
105
- return null;
106
- }
107
- }
108
- function persistOrgId(orgId) {
109
- try {
110
- if (typeof localStorage === "undefined") return;
111
- if (orgId) {
112
- localStorage.setItem(STORAGE_KEY, orgId);
113
- } else {
114
- localStorage.removeItem(STORAGE_KEY);
115
- }
116
- } catch {
117
- }
118
- }
119
- var useOrganizationStore = create((set) => ({
120
- currentOrg: null,
121
- userOrgs: [],
122
- members: [],
123
- teamPersonKinds: [],
124
- loading: false,
125
- setCurrentOrg: (org) => {
126
- setActiveTenantId(org?.id);
127
- persistOrgId(org?.id ?? null);
128
- set({ currentOrg: org });
129
- },
130
- // Sem `persistOrgId`: é a única diferença, e é toda a diferença.
131
- paintCurrentOrg: (org) => {
132
- setActiveTenantId(org?.id);
133
- set({ currentOrg: org });
134
- },
135
- setUserOrgs: (orgs) => set({ userOrgs: orgs }),
136
- setMembers: (members) => set({ members }),
137
- setTeamPersonKinds: (kinds) => set({ teamPersonKinds: kinds }),
138
- setLoading: (loading) => set({ loading }),
139
- reset: () => {
140
- setActiveTenantId(void 0);
141
- set({ currentOrg: null, userOrgs: [], members: [], loading: false });
142
- }
143
- }));
144
97
  var getSupabaseClientOptional = () => getSupabaseClientOptional$1();
145
98
 
146
- export { createFayzSupabaseClient, getFayzSupabaseClient, getFayzSupabaseClientOptional, getPersistedOrgId, getSupabaseClientOptional, persistOrgId, serviceBaseUrl, setServiceUrl, useOrganizationStore };
147
- //# sourceMappingURL=chunk-P6XUDT2P.js.map
148
- //# sourceMappingURL=chunk-P6XUDT2P.js.map
99
+ export { createFayzSupabaseClient, getFayzSupabaseClient, getFayzSupabaseClientOptional, getSupabaseClientOptional, serviceBaseUrl, setServiceUrl };
100
+ //# sourceMappingURL=chunk-KJELMULA.js.map
101
+ //# sourceMappingURL=chunk-KJELMULA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data/client.ts","../src/lib/supabase.ts"],"names":["headers","unit","tenant","_getOpt"],"mappings":"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","file":"chunk-KJELMULA.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/** Where the integration service answers, or null when everything stays on the edge. */\nexport function serviceBaseUrl(): string | null {\n return _serviceUrl\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","// 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"]}