@fayz-ai/saas 0.5.0 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/AdminShell.d.ts +14 -1
- package/dist/app/AdminShell.d.ts.map +1 -1
- package/dist/app/LoginPage.d.ts +2 -16
- package/dist/app/LoginPage.d.ts.map +1 -1
- package/dist/app/admin-app.d.ts +21 -0
- package/dist/app/admin-app.d.ts.map +1 -0
- package/dist/app/config.d.ts +40 -3
- package/dist/app/config.d.ts.map +1 -1
- package/dist/app/scaffold.d.ts +1 -2
- package/dist/app/scaffold.d.ts.map +1 -1
- package/dist/{chunk-DJW67TCY.js → chunk-DCRT47W4.js} +155 -28
- package/dist/chunk-DCRT47W4.js.map +1 -0
- package/dist/{chunk-QGMDVLLW.cjs → chunk-SRIUD35R.cjs} +155 -28
- package/dist/chunk-SRIUD35R.cjs.map +1 -0
- package/dist/crud/CrudDetailPage.d.ts.map +1 -1
- package/dist/index.cjs +1127 -5792
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +839 -5509
- package/dist/index.js.map +1 -1
- package/dist/org/adapters/supabase.d.ts +18 -0
- package/dist/org/adapters/supabase.d.ts.map +1 -1
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/index.cjs +11 -10
- package/dist/org/index.js +2 -1
- package/dist/shell/components/crud/archetypes/ClientOrdersTab.d.ts +4 -2
- package/dist/shell/components/crud/archetypes/ClientOrdersTab.d.ts.map +1 -1
- package/dist/shell/components/layout/BottomNav.d.ts.map +1 -1
- package/dist/shell/components/layout/CommandPalette.d.ts.map +1 -1
- package/dist/shell/components/organization/InviteMemberDialog.d.ts.map +1 -1
- package/dist/shell/components/organization/PermissionMatrixEditor.d.ts +6 -1
- package/dist/shell/components/organization/PermissionMatrixEditor.d.ts.map +1 -1
- package/dist/shell/components/organization/PermissionProfilesTab.d.ts.map +1 -1
- package/dist/shell/components/organization/TeamTab.d.ts.map +1 -1
- package/dist/shell/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
- package/dist/shell/components/settings/ConnectedUserProfile.d.ts +2 -1
- package/dist/shell/components/settings/ConnectedUserProfile.d.ts.map +1 -1
- package/dist/shell/components/settings/SettingsPage.d.ts +8 -1
- package/dist/shell/components/settings/SettingsPage.d.ts.map +1 -1
- package/dist/shell/config/theme/tokens.d.ts +12 -1
- package/dist/shell/config/theme/tokens.d.ts.map +1 -1
- package/dist/shell/config/theme/utils.d.ts +8 -0
- package/dist/shell/config/theme/utils.d.ts.map +1 -1
- package/dist/shell/lib/i18n.d.ts.map +1 -1
- package/dist/shell/types/client-orders.d.ts +4 -0
- package/dist/shell/types/client-orders.d.ts.map +1 -1
- package/dist/shell/types/crud.d.ts +4 -0
- package/dist/shell/types/crud.d.ts.map +1 -1
- package/package.json +7 -9
- package/src/app/AdminShell.tsx +103 -35
- package/src/app/LoginPage.tsx +2 -264
- package/src/app/{createFayzApp.tsx → admin-app.tsx} +98 -40
- package/src/app/config.ts +44 -2
- package/src/app/scaffold.tsx +13 -26
- package/src/crud/CrudDetailPage.tsx +43 -9
- package/src/crud/CrudPage.tsx +1 -1
- package/src/index.ts +12 -5
- package/src/org/adapters/supabase.ts +176 -28
- package/src/org/context.tsx +33 -2
- package/src/shell/components/crud/archetypes/ClientOrdersTab.tsx +12 -4
- package/src/shell/components/layout/BottomNav.tsx +39 -4
- package/src/shell/components/layout/CommandPalette.tsx +14 -10
- package/src/shell/components/organization/InviteMemberDialog.tsx +14 -3
- package/src/shell/components/organization/PermissionMatrixEditor.tsx +48 -10
- package/src/shell/components/organization/PermissionProfilesTab.tsx +65 -23
- package/src/shell/components/organization/TeamTab.tsx +36 -9
- package/src/shell/components/plugins/PluginSettingsPanel.tsx +5 -3
- package/src/shell/components/settings/ConnectedUserProfile.tsx +68 -25
- package/src/shell/components/settings/SettingsPage.tsx +12 -3
- package/src/shell/config/theme/tokens.ts +13 -1
- package/src/shell/config/theme/utils.ts +76 -15
- package/src/shell/lib/i18n.ts +4 -0
- package/src/shell/types/client-orders.ts +5 -0
- package/src/shell/types/crud.ts +4 -0
- package/dist/app/createFayzApp.d.ts +0 -11
- package/dist/app/createFayzApp.d.ts.map +0 -1
- package/dist/chunk-DJW67TCY.js.map +0 -1
- package/dist/chunk-QGMDVLLW.cjs.map +0 -1
- package/dist/shell/components/organization/ImpersonationBanner.d.ts +0 -3
- package/dist/shell/components/organization/ImpersonationBanner.d.ts.map +0 -1
- package/dist/shell/components/settings/ConnectedHolidaysSettings.d.ts +0 -3
- package/dist/shell/components/settings/ConnectedHolidaysSettings.d.ts.map +0 -1
- package/dist/shell/components/settings/ConnectedLocationsOverview.d.ts +0 -3
- package/dist/shell/components/settings/ConnectedLocationsOverview.d.ts.map +0 -1
- package/dist/shell/createSaasApp.d.ts +0 -145
- package/dist/shell/createSaasApp.d.ts.map +0 -1
- package/src/shell/components/organization/ImpersonationBanner.tsx +0 -29
- package/src/shell/components/settings/ConnectedHolidaysSettings.tsx +0 -99
- package/src/shell/components/settings/ConnectedLocationsOverview.tsx +0 -57
- package/src/shell/createSaasApp.tsx +0 -943
package/dist/app/AdminShell.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type ModuleNavVariant } from '@fayz-ai/ui';
|
|
2
|
+
import { type BottomNavItem, type MobileHeaderVariant, type ModuleNavVariant } from '@fayz-ai/ui';
|
|
3
3
|
import type { CustomPage } from './config';
|
|
4
4
|
import type { AuthProvider } from '@fayz-ai/core';
|
|
5
5
|
export interface AdminShellProps {
|
|
@@ -16,12 +16,25 @@ export interface AdminShellProps {
|
|
|
16
16
|
oauthProviders?: Exclude<AuthProvider, 'email'>[];
|
|
17
17
|
showSettings?: boolean;
|
|
18
18
|
showOrgSettings?: boolean;
|
|
19
|
+
/** Show the workspace/org switcher at the sidebar top. Default: true.
|
|
20
|
+
* Single-org apps (config.org.multiOrg === false) get false from the
|
|
21
|
+
* scaffold so B2C users never see an organization concept. */
|
|
22
|
+
showOrgSwitcher?: boolean;
|
|
23
|
+
/** Show the branding ("Identidade Visual") + company "Geral" settings tabs.
|
|
24
|
+
* Default: true. B2C apps pass false to hide org-identity settings. */
|
|
25
|
+
showBranding?: boolean;
|
|
19
26
|
/** Wrap the main content in an inset "framed" card (default: true). The
|
|
20
27
|
* sidebar is always flush/full-height. */
|
|
21
28
|
contentFrame?: boolean;
|
|
22
29
|
/** How module-internal navigation renders. Defaults to 'tabs' for the
|
|
23
30
|
* 'sidebar' layout and 'rail' for 'topbar'. */
|
|
24
31
|
moduleNav?: ModuleNavVariant;
|
|
32
|
+
/** Mobile bottom tab bar, passed straight through to AppShell. */
|
|
33
|
+
bottomNav?: BottomNavItem[];
|
|
34
|
+
/** Fired when a bottom-nav `action` item (e.g. the center "+") is tapped. */
|
|
35
|
+
onBottomNavAction?: (id: string) => void;
|
|
36
|
+
/** Mobile header treatment (<md), passed straight through to AppShell. */
|
|
37
|
+
mobileHeader?: MobileHeaderVariant;
|
|
25
38
|
}
|
|
26
39
|
/** The shell + an auth gate in front of it. */
|
|
27
40
|
export declare function AdminShell(props: AdminShellProps): React.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminShell.d.ts","sourceRoot":"","sources":["../../src/app/AdminShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,
|
|
1
|
+
{"version":3,"file":"AdminShell.d.ts","sourceRoot":"","sources":["../../src/app/AdminShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAGxB,KAAK,gBAAgB,EAWtB,MAAM,aAAa,CAAA;AAQpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAmBjD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAA;IACzC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC3B,WAAW,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAA;IACjD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;mEAE+D;IAC/D,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;4EACwE;IACxE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;+CAC2C;IAC3C,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;oDACgD;IAChD,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B,kEAAkE;IAClE,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;IAC3B,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,0EAA0E;IAC1E,YAAY,CAAC,EAAE,mBAAmB,CAAA;CACnC;AAkaD,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,qBAgBhD;yBAhBe,UAAU"}
|
package/dist/app/LoginPage.d.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export interface LoginPageProps {
|
|
4
|
-
appName?: string;
|
|
5
|
-
logo?: React.ReactNode;
|
|
6
|
-
loginLogo?: React.ReactNode;
|
|
7
|
-
layout?: 'split' | 'centered';
|
|
8
|
-
tagline?: string;
|
|
9
|
-
description?: string;
|
|
10
|
-
showOAuth?: boolean;
|
|
11
|
-
oauthProviders?: Exclude<AuthProvider, 'email'>[];
|
|
12
|
-
}
|
|
13
|
-
export declare function LoginPage({ appName, logo, loginLogo, layout, tagline, description, showOAuth, oauthProviders, }: LoginPageProps): React.JSX.Element;
|
|
14
|
-
export declare namespace LoginPage {
|
|
15
|
-
var displayName: string;
|
|
16
|
-
}
|
|
1
|
+
export { LoginPage } from '@fayz-ai/plugin-auth';
|
|
2
|
+
export type { LoginPageProps } from '@fayz-ai/plugin-auth';
|
|
17
3
|
//# sourceMappingURL=LoginPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoginPage.d.ts","sourceRoot":"","sources":["../../src/app/LoginPage.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"LoginPage.d.ts","sourceRoot":"","sources":["../../src/app/LoginPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type AuthLayout } from '@fayz-ai/plugin-auth';
|
|
3
|
+
import type { FayzAppConfig } from './config';
|
|
4
|
+
export declare function getAuthShellProps(auth: FayzAppConfig['auth']): {
|
|
5
|
+
requireAuth?: boolean;
|
|
6
|
+
loginTagline?: string;
|
|
7
|
+
loginDescription?: string;
|
|
8
|
+
loginLogo?: React.ReactNode;
|
|
9
|
+
loginLayout?: AuthLayout;
|
|
10
|
+
showOAuth?: boolean;
|
|
11
|
+
oauthProviders?: Exclude<import('@fayz-ai/core').AuthProvider, 'email'>[];
|
|
12
|
+
};
|
|
13
|
+
export declare function AdminProviders({ config, children }: {
|
|
14
|
+
config: FayzAppConfig;
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
export declare namespace AdminProviders {
|
|
18
|
+
var displayName: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function createFayzApp(config: FayzAppConfig): React.ComponentType;
|
|
21
|
+
//# sourceMappingURL=admin-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-app.d.ts","sourceRoot":"","sources":["../../src/app/admin-app.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAU9B,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,sBAAsB,CAAA;AAiB7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAuC7C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC3B,WAAW,CAAC,EAAE,UAAU,CAAA;IACxB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC,OAAO,eAAe,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,CAAA;CAC1E,CAsBA;AAoGD,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAwExG;yBAxEe,cAAc;;;AAoF9B,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,KAAK,CAAC,aAAa,CAyBxE"}
|
package/dist/app/config.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { AuthProvider, OrgAdapter, PluginManifest, ThemeMode, LocaleConfig, PermissionsConfig } from '@fayz-ai/core';
|
|
3
|
+
import type { AuthPluginOptions, ResolvedAuthPlugin } from '@fayz-ai/plugin-auth';
|
|
4
|
+
import type { BottomNavItem, MobileHeaderVariant } from '@fayz-ai/ui';
|
|
3
5
|
import type { SaasTheme } from '../shell/config/theme/tokens';
|
|
4
6
|
import type { CreateThemeOptions } from '../shell/config/theme/utils';
|
|
5
7
|
import type { PlanConfig } from '../shell/types/billing';
|
|
@@ -19,13 +21,28 @@ export interface CustomPage {
|
|
|
19
21
|
feature: string;
|
|
20
22
|
action: 'read' | 'create' | 'edit' | 'delete';
|
|
21
23
|
};
|
|
24
|
+
/** Show this page in the sidebar/topbar navigation. Default: true. Set `false`
|
|
25
|
+
* for mobile-only pages reachable via bottomNav/avatar (e.g. a "Mais" overflow
|
|
26
|
+
* hub or a "Perfil" avatar target): the route still works, but the entry is
|
|
27
|
+
* hidden from desktop navigation where those mobile constructs are meaningless. */
|
|
28
|
+
nav?: boolean;
|
|
22
29
|
children?: CustomPage[];
|
|
23
30
|
}
|
|
24
31
|
export interface AuthConfig {
|
|
25
32
|
/** 'supabase' | 'mock' or bring your own AuthAdapter */
|
|
26
|
-
adapter?: '
|
|
33
|
+
adapter?: AuthPluginOptions['adapter'];
|
|
34
|
+
/** New plugin-auth provider selector. Existing apps may keep using adapter. */
|
|
35
|
+
provider?: AuthPluginOptions['provider'];
|
|
27
36
|
/** Redirect to login when no session is found (default: true) */
|
|
28
37
|
requireAuth?: boolean;
|
|
38
|
+
/** New plugin-auth route and provider options. */
|
|
39
|
+
routes?: AuthPluginOptions['routes'];
|
|
40
|
+
supabase?: AuthPluginOptions['supabase'];
|
|
41
|
+
oauth?: AuthPluginOptions['oauth'];
|
|
42
|
+
layout?: AuthPluginOptions['layout'];
|
|
43
|
+
logo?: ReactNode;
|
|
44
|
+
tagline?: string;
|
|
45
|
+
description?: string;
|
|
29
46
|
loginLogo?: ReactNode;
|
|
30
47
|
loginLayout?: 'split' | 'centered';
|
|
31
48
|
loginTagline?: string;
|
|
@@ -33,6 +50,7 @@ export interface AuthConfig {
|
|
|
33
50
|
showOAuth?: boolean;
|
|
34
51
|
oauthProviders?: Exclude<AuthProvider, 'email'>[];
|
|
35
52
|
}
|
|
53
|
+
export type AppAuthConfig = AuthConfig | ResolvedAuthPlugin;
|
|
36
54
|
export interface OrgConfig {
|
|
37
55
|
/** 'supabase' | 'mock' or bring your own OrgAdapter */
|
|
38
56
|
adapter?: 'supabase' | 'mock' | OrgAdapter;
|
|
@@ -58,7 +76,7 @@ export interface FayzAppConfig {
|
|
|
58
76
|
logo?: string | ReactNode;
|
|
59
77
|
supabaseUrl?: string;
|
|
60
78
|
supabaseAnonKey?: string;
|
|
61
|
-
auth?:
|
|
79
|
+
auth?: AppAuthConfig;
|
|
62
80
|
org?: OrgConfig;
|
|
63
81
|
plugins?: PluginManifest[];
|
|
64
82
|
pages?: CustomPage[];
|
|
@@ -66,6 +84,17 @@ export interface FayzAppConfig {
|
|
|
66
84
|
defaultThemeMode?: ThemeMode;
|
|
67
85
|
/** Shell layout variant (default: 'sidebar') */
|
|
68
86
|
layout?: 'sidebar' | 'topbar' | 'minimal';
|
|
87
|
+
/** Mobile bottom tab bar. Rendered by AppShell on small screens (md:hidden)
|
|
88
|
+
* for every layout variant. Route items map a lucide icon name to a route; an
|
|
89
|
+
* `{ kind: 'action', id, icon }` item renders as a raised center button
|
|
90
|
+
* (Mobills style) that fires `onBottomNavAction(id)` instead of navigating. */
|
|
91
|
+
bottomNav?: BottomNavItem[];
|
|
92
|
+
/** Fired when a bottom-nav `action` item (e.g. the center "+") is tapped. */
|
|
93
|
+
onBottomNavAction?: (id: string) => void;
|
|
94
|
+
/** Mobile header treatment (<md), default 'minimal'. 'transparent' renders no
|
|
95
|
+
* header bar (edge-to-edge content) with a floating profile avatar top-right;
|
|
96
|
+
* 'hidden' renders neither. Desktop keeps its sidebar + user menu. */
|
|
97
|
+
mobileHeader?: MobileHeaderVariant;
|
|
69
98
|
/** Wrap the main content in an inset "framed" card (default: true). The
|
|
70
99
|
* sidebar itself is always flush/full-height. */
|
|
71
100
|
contentFrame?: boolean;
|
|
@@ -76,6 +105,14 @@ export interface FayzAppConfig {
|
|
|
76
105
|
* view changes). Default: 'slide'. Set per repo/app for a different feel. */
|
|
77
106
|
navTransition?: 'slide' | 'fade' | 'none';
|
|
78
107
|
locale?: LocaleConfig;
|
|
108
|
+
/** Show org-level settings tabs (Equipe/Permissões/Localizações/Regras).
|
|
109
|
+
* Defaults to `Boolean(org)` for back-compat. B2C/personal apps that still
|
|
110
|
+
* need an org for the workspace can set `false` to hide these ERP tabs. */
|
|
111
|
+
orgSettings?: boolean;
|
|
112
|
+
/** Show the branding ("Identidade Visual") + company "Geral" settings tabs.
|
|
113
|
+
* Default: `true`. B2C apps set `false` to drop org-identity settings, leaving
|
|
114
|
+
* Perfil + Segurança + plugin settings only. */
|
|
115
|
+
branding?: boolean;
|
|
79
116
|
permissions?: PermissionsConfig;
|
|
80
117
|
billing?: FayzBillingConfig;
|
|
81
118
|
chat?: ChatConfig;
|
package/dist/app/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/app/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACrD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/app/config.ts"],"names":[],"mappings":"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"}
|
package/dist/app/scaffold.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { AppManifest } from '@fayz-ai/core';
|
|
3
3
|
import type { FayzAppConfig } from './config';
|
|
4
|
-
import { type SaasAppConfig } from '../shell/createSaasApp';
|
|
5
4
|
/** Fayz/Saas config → AppManifest (sugar → data). During the Beauty/Resto
|
|
6
5
|
* migration, config-authored apps keep a live config ref so renderApp can
|
|
7
6
|
* preserve code-backed plugins and custom pages while the JSON manifest path
|
|
8
7
|
* matures. Serialized manifests still resolve through plugin/page registries. */
|
|
9
|
-
export declare function defineSaas(config: FayzAppConfig
|
|
8
|
+
export declare function defineSaas(config: FayzAppConfig): AppManifest;
|
|
10
9
|
export declare function AdminScaffold({ manifest, surface }: {
|
|
11
10
|
manifest: AppManifest;
|
|
12
11
|
surface: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/app/scaffold.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,OAAO,KAAK,EACV,WAAW,EAKZ,MAAM,eAAe,CAAA;AAGtB,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/app/scaffold.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,OAAO,KAAK,EACV,WAAW,EAKZ,MAAM,eAAe,CAAA;AAGtB,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,UAAU,CAAA;AA2BzD;;;iFAGiF;AACjF,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CA0B7D;AA6DD,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IAAE,QAAQ,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,qBAsB9F;yBAtBe,aAAa"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { usePermissionsStore } from './chunk-XNWCGJYH.js';
|
|
1
2
|
import { createClient } from '@supabase/supabase-js';
|
|
2
3
|
import { setActiveTenantId, setGlobalSupabaseClient } from '@fayz-ai/core';
|
|
3
4
|
import { create } from 'zustand';
|
|
@@ -5,7 +6,6 @@ import * as React from 'react';
|
|
|
5
6
|
import { useAuthStore } from '@fayz-ai/auth';
|
|
6
7
|
import { jsx } from 'react/jsx-runtime';
|
|
7
8
|
|
|
8
|
-
// src/supabase/client.ts
|
|
9
9
|
var CORE_SCHEMA = "saas_core";
|
|
10
10
|
var _client = null;
|
|
11
11
|
function createFayzSupabaseClient(url, anonKey) {
|
|
@@ -80,7 +80,8 @@ function mapMemberRow(row) {
|
|
|
80
80
|
fullName: profile["full_name"] ?? "",
|
|
81
81
|
avatarUrl: profile["avatar_url"] ?? void 0
|
|
82
82
|
},
|
|
83
|
-
|
|
83
|
+
// tenant_members has no `joined_at` column — it's `created_at`.
|
|
84
|
+
joinedAt: row["joined_at"] ?? row["created_at"]
|
|
84
85
|
};
|
|
85
86
|
}
|
|
86
87
|
function mapLocationRow(row) {
|
|
@@ -113,18 +114,46 @@ function mapInviteRow(row) {
|
|
|
113
114
|
expiresAt: row["expires_at"]
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
|
-
var
|
|
117
|
-
|
|
117
|
+
var DB_ACTION = {
|
|
118
|
+
read: "read",
|
|
119
|
+
create: "create",
|
|
120
|
+
edit: "update",
|
|
121
|
+
write: "create",
|
|
122
|
+
manage: "manage",
|
|
123
|
+
delete: "delete"
|
|
124
|
+
};
|
|
125
|
+
function slugifyRole(name) {
|
|
126
|
+
return name.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "role";
|
|
127
|
+
}
|
|
128
|
+
var DEFAULT_ROLES = [
|
|
129
|
+
{ id: "owner", name: "Owner" },
|
|
130
|
+
{ id: "admin", name: "Admin" },
|
|
131
|
+
{ id: "manager", name: "Manager" },
|
|
132
|
+
{ id: "staff", name: "Staff" },
|
|
133
|
+
{ id: "viewer", name: "Viewer" }
|
|
134
|
+
];
|
|
135
|
+
var SYSTEM_PERMISSION_MAP = {
|
|
136
|
+
"team.read": "manage_team",
|
|
137
|
+
"team.invite": "manage_team",
|
|
138
|
+
"team.manage": "manage_team",
|
|
139
|
+
"team.manage_roles": "manage_permissions",
|
|
140
|
+
"billing.read": "manage_billing",
|
|
141
|
+
"billing.manage": "manage_billing",
|
|
142
|
+
"settings.read": "manage_settings",
|
|
143
|
+
"settings.update": "manage_settings"
|
|
144
|
+
};
|
|
145
|
+
var ALL_SYSTEM_PERMISSIONS = ["manage_team", "manage_billing", "manage_settings", "manage_permissions"];
|
|
146
|
+
function buildPermissionProfiles(roles, permissions, rolePerms, overrides) {
|
|
118
147
|
const overrideMap = /* @__PURE__ */ new Map();
|
|
119
148
|
for (const o of overrides) {
|
|
120
149
|
overrideMap.set(`${o.role}:${o.permission_id}`, o.granted);
|
|
121
150
|
}
|
|
122
151
|
const rolePermMap = /* @__PURE__ */ new Map();
|
|
123
|
-
for (const
|
|
124
|
-
rolePermMap.set(
|
|
152
|
+
for (const r of roles) {
|
|
153
|
+
rolePermMap.set(r.id, /* @__PURE__ */ new Set());
|
|
125
154
|
}
|
|
126
|
-
|
|
127
|
-
rolePermMap.get("owner").add(p.id);
|
|
155
|
+
if (rolePermMap.has("owner")) {
|
|
156
|
+
for (const p of permissions) rolePermMap.get("owner").add(p.id);
|
|
128
157
|
}
|
|
129
158
|
for (const rp of rolePerms) {
|
|
130
159
|
rolePermMap.get(rp.role)?.add(rp.permission_id);
|
|
@@ -143,14 +172,14 @@ function buildPermissionProfiles(permissions, rolePerms, overrides) {
|
|
|
143
172
|
}
|
|
144
173
|
const actionMap = {
|
|
145
174
|
read: "read",
|
|
146
|
-
create: "
|
|
147
|
-
update: "
|
|
148
|
-
manage: "
|
|
175
|
+
create: "create",
|
|
176
|
+
update: "edit",
|
|
177
|
+
manage: "edit",
|
|
149
178
|
delete: "delete",
|
|
150
|
-
configure: "
|
|
151
|
-
invite: "
|
|
179
|
+
configure: "edit",
|
|
180
|
+
invite: "create"
|
|
152
181
|
};
|
|
153
|
-
return
|
|
182
|
+
return roles.map(({ id: role, name, description, isSystem }) => {
|
|
154
183
|
const permIds = rolePermMap.get(role);
|
|
155
184
|
const features = {};
|
|
156
185
|
for (const permId of permIds) {
|
|
@@ -165,16 +194,26 @@ function buildPermissionProfiles(permissions, rolePerms, overrides) {
|
|
|
165
194
|
features[category].push(mappedAction);
|
|
166
195
|
}
|
|
167
196
|
}
|
|
197
|
+
const systemPermissions = [];
|
|
198
|
+
const source = role === "owner" ? ALL_SYSTEM_PERMISSIONS : [...permIds].map((id) => SYSTEM_PERMISSION_MAP[id]);
|
|
199
|
+
for (const sp of source) {
|
|
200
|
+
if (sp && !systemPermissions.includes(sp)) systemPermissions.push(sp);
|
|
201
|
+
}
|
|
168
202
|
return {
|
|
169
203
|
id: role,
|
|
170
|
-
name: capitalize(role),
|
|
171
|
-
|
|
204
|
+
name: name || capitalize(role),
|
|
205
|
+
description,
|
|
206
|
+
isSystem: isSystem ?? true,
|
|
207
|
+
systemPermissions,
|
|
172
208
|
grants: features
|
|
173
209
|
};
|
|
174
210
|
});
|
|
175
211
|
}
|
|
176
212
|
function createSupabaseOrgAdapter(config) {
|
|
177
213
|
const schema = config?.coreSchema ?? CORE_SCHEMA;
|
|
214
|
+
const roles = config?.roles && config.roles.length > 0 ? config.roles : DEFAULT_ROLES;
|
|
215
|
+
const authAdapter = config?.authAdapter;
|
|
216
|
+
const inviteRedirectTo = typeof window !== "undefined" ? `${window.location.origin}/` : void 0;
|
|
178
217
|
function supabase() {
|
|
179
218
|
return getFayzSupabaseClient();
|
|
180
219
|
}
|
|
@@ -253,24 +292,64 @@ function createSupabaseOrgAdapter(config) {
|
|
|
253
292
|
if (error) throw error;
|
|
254
293
|
},
|
|
255
294
|
async listProfiles(orgId) {
|
|
256
|
-
const [permsResult, rolePermsResult, overridesResult] = await Promise.all([
|
|
295
|
+
const [permsResult, rolePermsResult, overridesResult, customResult] = await Promise.all([
|
|
257
296
|
core().from("permissions").select("id, category"),
|
|
258
297
|
core().from("role_permissions").select("role, permission_id"),
|
|
259
|
-
core().from("tenant_role_overrides").select("role, permission_id, granted").eq("tenant_id", orgId)
|
|
298
|
+
core().from("tenant_role_overrides").select("role, permission_id, granted").eq("tenant_id", orgId),
|
|
299
|
+
// Custom roles the tenant created by duplicating a system role. Tolerate a
|
|
300
|
+
// missing table (pre-seed) — just show the system roles in that case.
|
|
301
|
+
core().from("tenant_roles").select("key, name, description").eq("tenant_id", orgId)
|
|
260
302
|
]);
|
|
261
303
|
if (permsResult.error) throw permsResult.error;
|
|
262
304
|
if (rolePermsResult.error) throw rolePermsResult.error;
|
|
263
305
|
if (overridesResult.error) throw overridesResult.error;
|
|
306
|
+
const systemRoles = roles.map((r) => ({ ...r, isSystem: true }));
|
|
307
|
+
const customRoles = customResult.error ? [] : (customResult.data ?? []).map((r) => ({
|
|
308
|
+
id: r.key,
|
|
309
|
+
name: r.name,
|
|
310
|
+
description: r.description ?? void 0,
|
|
311
|
+
isSystem: false
|
|
312
|
+
}));
|
|
264
313
|
return buildPermissionProfiles(
|
|
314
|
+
[...systemRoles, ...customRoles],
|
|
265
315
|
permsResult.data ?? [],
|
|
266
316
|
rolePermsResult.data ?? [],
|
|
267
317
|
overridesResult.data ?? []
|
|
268
318
|
);
|
|
269
319
|
},
|
|
270
|
-
async createProfile(
|
|
271
|
-
|
|
272
|
-
"
|
|
320
|
+
async createProfile(orgId, profile) {
|
|
321
|
+
const existing = new Set(
|
|
322
|
+
((await core().from("tenant_roles").select("key").eq("tenant_id", orgId)).data ?? []).map((r) => r.key)
|
|
273
323
|
);
|
|
324
|
+
let key = slugifyRole(profile.name);
|
|
325
|
+
if (existing.has(key) || roles.some((r) => r.id === key)) {
|
|
326
|
+
let n = 2;
|
|
327
|
+
while (existing.has(`${key}-${n}`) || roles.some((r) => r.id === `${key}-${n}`)) n++;
|
|
328
|
+
key = `${key}-${n}`;
|
|
329
|
+
}
|
|
330
|
+
const insertRole = await core().from("tenant_roles").insert({ tenant_id: orgId, key, name: profile.name, description: profile.description ?? null });
|
|
331
|
+
if (insertRole.error) throw insertRole.error;
|
|
332
|
+
const overrides = Object.entries(profile.grants ?? {}).flatMap(
|
|
333
|
+
([category, actions]) => actions.map((action) => ({
|
|
334
|
+
tenant_id: orgId,
|
|
335
|
+
role: key,
|
|
336
|
+
permission_id: `${category}.${DB_ACTION[action] ?? action}`,
|
|
337
|
+
granted: true
|
|
338
|
+
}))
|
|
339
|
+
);
|
|
340
|
+
if (overrides.length > 0) {
|
|
341
|
+
const { error } = await core().from("tenant_role_overrides").insert(overrides);
|
|
342
|
+
if (error) throw error;
|
|
343
|
+
}
|
|
344
|
+
const profiles = await this.listProfiles(orgId);
|
|
345
|
+
return profiles.find((p) => p.id === key) ?? {
|
|
346
|
+
id: key,
|
|
347
|
+
name: profile.name,
|
|
348
|
+
description: profile.description,
|
|
349
|
+
isSystem: false,
|
|
350
|
+
systemPermissions: profile.systemPermissions ?? [],
|
|
351
|
+
grants: profile.grants ?? {}
|
|
352
|
+
};
|
|
274
353
|
},
|
|
275
354
|
async updateProfile(orgId, profileId, data) {
|
|
276
355
|
if (data.grants) {
|
|
@@ -280,6 +359,8 @@ function createSupabaseOrgAdapter(config) {
|
|
|
280
359
|
for (const action of actions) {
|
|
281
360
|
const dbActionMap = {
|
|
282
361
|
read: "read",
|
|
362
|
+
create: "create",
|
|
363
|
+
edit: "update",
|
|
283
364
|
write: "create",
|
|
284
365
|
manage: "manage",
|
|
285
366
|
delete: "delete"
|
|
@@ -303,8 +384,13 @@ function createSupabaseOrgAdapter(config) {
|
|
|
303
384
|
if (!updated) throw new Error(`Profile not found: ${profileId}`);
|
|
304
385
|
return updated;
|
|
305
386
|
},
|
|
306
|
-
async deleteProfile(
|
|
307
|
-
|
|
387
|
+
async deleteProfile(orgId, profileId) {
|
|
388
|
+
const found = await core().from("tenant_roles").select("key").eq("tenant_id", orgId).eq("key", profileId).maybeSingle();
|
|
389
|
+
if (found.error) throw found.error;
|
|
390
|
+
if (!found.data) throw new Error("System roles cannot be deleted.");
|
|
391
|
+
await core().from("tenant_role_overrides").delete().eq("tenant_id", orgId).eq("role", profileId);
|
|
392
|
+
const { error } = await core().from("tenant_roles").delete().eq("tenant_id", orgId).eq("key", profileId);
|
|
393
|
+
if (error) throw error;
|
|
308
394
|
},
|
|
309
395
|
async listInvites(orgId) {
|
|
310
396
|
const { data, error } = await core().from("invitations").select("*").eq("tenant_id", orgId).order("created_at", { ascending: false });
|
|
@@ -319,6 +405,10 @@ function createSupabaseOrgAdapter(config) {
|
|
|
319
405
|
invited_by: invitedBy
|
|
320
406
|
}).select().single();
|
|
321
407
|
if (error) throw error;
|
|
408
|
+
await authAdapter?.inviteUser?.(email, {
|
|
409
|
+
redirectTo: inviteRedirectTo,
|
|
410
|
+
data: { tenant_id: orgId, role: profileId, invited_by: invitedBy }
|
|
411
|
+
});
|
|
322
412
|
return mapInviteRow(data);
|
|
323
413
|
},
|
|
324
414
|
async bulkInvite(orgId, emails, profileId, invitedBy) {
|
|
@@ -330,6 +420,14 @@ function createSupabaseOrgAdapter(config) {
|
|
|
330
420
|
}));
|
|
331
421
|
const { data, error } = await core().from("invitations").insert(rows).select();
|
|
332
422
|
if (error) throw error;
|
|
423
|
+
await Promise.all(
|
|
424
|
+
emails.map(
|
|
425
|
+
(email) => authAdapter?.inviteUser?.(email, {
|
|
426
|
+
redirectTo: inviteRedirectTo,
|
|
427
|
+
data: { tenant_id: orgId, role: profileId, invited_by: invitedBy }
|
|
428
|
+
})
|
|
429
|
+
)
|
|
430
|
+
);
|
|
333
431
|
return (data ?? []).map(mapInviteRow);
|
|
334
432
|
},
|
|
335
433
|
async revokeInvite(orgId, inviteId) {
|
|
@@ -342,7 +440,12 @@ function createSupabaseOrgAdapter(config) {
|
|
|
342
440
|
expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1e3).toISOString()
|
|
343
441
|
}).eq("id", inviteId).eq("tenant_id", orgId).select().single();
|
|
344
442
|
if (error) throw error;
|
|
345
|
-
|
|
443
|
+
const row = data;
|
|
444
|
+
await authAdapter?.inviteUser?.(row.email, {
|
|
445
|
+
redirectTo: inviteRedirectTo,
|
|
446
|
+
data: { tenant_id: orgId, role: row.role, invited_by: row.invited_by }
|
|
447
|
+
});
|
|
448
|
+
return mapInviteRow(row);
|
|
346
449
|
},
|
|
347
450
|
async listLocations(orgId) {
|
|
348
451
|
const { data, error } = await core().from("locations").select("*").eq("tenant_id", orgId).order("is_headquarters", { ascending: false }).order("name");
|
|
@@ -698,9 +801,27 @@ function useTenantOptional() {
|
|
|
698
801
|
}
|
|
699
802
|
function OrgProvider({ adapter, autoCreate = false, children }) {
|
|
700
803
|
const { user } = useAuthStore();
|
|
701
|
-
const { currentOrg, userOrgs, loading, setCurrentOrg, setUserOrgs, setLoading, reset } = useOrganizationStore();
|
|
804
|
+
const { currentOrg, userOrgs, loading, setCurrentOrg, setUserOrgs, setMembers, setLoading, reset } = useOrganizationStore();
|
|
805
|
+
const setProfiles = usePermissionsStore((s) => s.setProfiles);
|
|
806
|
+
const setCurrentProfile = usePermissionsStore((s) => s.setCurrentProfile);
|
|
702
807
|
const adapterRef = React.useRef(adapter);
|
|
703
808
|
adapterRef.current = adapter;
|
|
809
|
+
const hydrateOrg = React.useCallback(
|
|
810
|
+
async (orgId, uid) => {
|
|
811
|
+
try {
|
|
812
|
+
const [members, profiles] = await Promise.all([
|
|
813
|
+
adapterRef.current.listMembers(orgId),
|
|
814
|
+
adapterRef.current.listProfiles(orgId)
|
|
815
|
+
]);
|
|
816
|
+
setMembers(members);
|
|
817
|
+
setProfiles(profiles);
|
|
818
|
+
const myMembership = uid ? members.find((m) => m.userId === uid) : void 0;
|
|
819
|
+
setCurrentProfile(profiles.find((p) => p.id === myMembership?.profileId) ?? null);
|
|
820
|
+
} catch {
|
|
821
|
+
}
|
|
822
|
+
},
|
|
823
|
+
[setMembers, setProfiles, setCurrentProfile]
|
|
824
|
+
);
|
|
704
825
|
React.useEffect(() => {
|
|
705
826
|
if (!user) {
|
|
706
827
|
reset();
|
|
@@ -729,6 +850,7 @@ function OrgProvider({ adapter, autoCreate = false, children }) {
|
|
|
729
850
|
}
|
|
730
851
|
]);
|
|
731
852
|
setCurrentOrg(newOrg);
|
|
853
|
+
await hydrateOrg(newOrg.id, user.id);
|
|
732
854
|
}
|
|
733
855
|
return;
|
|
734
856
|
}
|
|
@@ -736,7 +858,10 @@ function OrgProvider({ adapter, autoCreate = false, children }) {
|
|
|
736
858
|
const target = memberships.find((m) => m.orgId === persistedId) ?? memberships[0];
|
|
737
859
|
if (target && !cancelled) {
|
|
738
860
|
const org = await adapterRef.current.getOrg(target.orgId);
|
|
739
|
-
if (!cancelled)
|
|
861
|
+
if (!cancelled) {
|
|
862
|
+
setCurrentOrg(org);
|
|
863
|
+
await hydrateOrg(org.id, user.id);
|
|
864
|
+
}
|
|
740
865
|
}
|
|
741
866
|
} finally {
|
|
742
867
|
if (!cancelled) setLoading(false);
|
|
@@ -752,6 +877,7 @@ function OrgProvider({ adapter, autoCreate = false, children }) {
|
|
|
752
877
|
try {
|
|
753
878
|
const org = await adapterRef.current.getOrg(orgId);
|
|
754
879
|
setCurrentOrg(org);
|
|
880
|
+
await hydrateOrg(org.id, user?.id);
|
|
755
881
|
} finally {
|
|
756
882
|
setLoading(false);
|
|
757
883
|
}
|
|
@@ -762,6 +888,7 @@ function OrgProvider({ adapter, autoCreate = false, children }) {
|
|
|
762
888
|
try {
|
|
763
889
|
const org = await adapterRef.current.getOrg(currentOrg.id);
|
|
764
890
|
setCurrentOrg(org);
|
|
891
|
+
await hydrateOrg(org.id, user?.id);
|
|
765
892
|
} finally {
|
|
766
893
|
setLoading(false);
|
|
767
894
|
}
|
|
@@ -777,5 +904,5 @@ function OrgProvider({ adapter, autoCreate = false, children }) {
|
|
|
777
904
|
}
|
|
778
905
|
|
|
779
906
|
export { CORE_SCHEMA, OrgProvider, createFayzSupabaseClient, createMockOrgAdapter, createSupabaseOrgAdapter, getCoreSchemaClient, getFayzSupabaseClient, getFayzSupabaseClientOptional, getPersistedOrgId, useOrgAdapter, useOrgAdapterOptional, useOrganizationStore, useTenant, useTenantOptional };
|
|
780
|
-
//# sourceMappingURL=chunk-
|
|
781
|
-
//# sourceMappingURL=chunk-
|
|
907
|
+
//# sourceMappingURL=chunk-DCRT47W4.js.map
|
|
908
|
+
//# sourceMappingURL=chunk-DCRT47W4.js.map
|