@choiceform/shared-auth 0.1.11 → 0.1.13
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/README.md +47 -25
- package/dist/components/protected-route.d.ts +1 -1
- package/dist/components/protected-route.d.ts.map +1 -1
- package/dist/components/protected-route.js +9 -3
- package/dist/components/sign-in-page.d.ts +3 -2
- package/dist/components/sign-in-page.d.ts.map +1 -1
- package/dist/components/sign-in-page.js +5 -7
- package/dist/config.d.ts +11 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -2
- package/dist/core/init-auth-sync.d.ts +7 -0
- package/dist/core/init-auth-sync.d.ts.map +1 -0
- package/dist/core/init-auth-sync.js +34 -0
- package/dist/core.d.ts +1 -1
- package/dist/init.d.ts +14 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +18 -6
- package/dist/store/actions.d.ts +3 -1
- package/dist/store/actions.d.ts.map +1 -1
- package/dist/store/actions.js +13 -5
- package/package.json +9 -9
- package/LICENSE.md +0 -149
package/README.md
CHANGED
|
@@ -54,19 +54,25 @@ import { adminClient, organizationClient } from "better-auth/client/plugins"
|
|
|
54
54
|
export const auth = initAuth({
|
|
55
55
|
baseURL: import.meta.env.VITE_AUTH_API_URL || "http://localhost:4320",
|
|
56
56
|
tokenStorageKey: "auth-token",
|
|
57
|
-
|
|
58
|
-
signInPath: "/sign-in",
|
|
57
|
+
// 可选:如果你想自定义插件
|
|
59
58
|
plugins: [adminClient(), organizationClient({ teams: { enabled: true } })],
|
|
60
59
|
})
|
|
60
|
+
|
|
61
|
+
// 注意:导航相关配置已移至组件层面:
|
|
62
|
+
// - 登录成功后的导航:在 SignInPage 组件中通过 onAuthSuccess 回调处理
|
|
63
|
+
// - 未授权时的导航:在 ProtectedRoute 组件中通过 onUnauthorized 回调处理
|
|
64
|
+
// - 登出后的导航:在调用 signOut 时传入 redirectTo 参数
|
|
61
65
|
```
|
|
62
66
|
|
|
63
67
|
### 2. 在应用中使用
|
|
64
68
|
|
|
65
69
|
```typescript
|
|
66
70
|
import { AuthSync, ProtectedRoute, useAuthInit } from "@choiceform/shared-auth"
|
|
71
|
+
import { useNavigate } from "react-router"
|
|
67
72
|
import { auth } from "./lib/auth"
|
|
68
73
|
|
|
69
74
|
function App() {
|
|
75
|
+
const navigate = useNavigate()
|
|
70
76
|
useAuthInit(auth)
|
|
71
77
|
|
|
72
78
|
return (
|
|
@@ -77,7 +83,10 @@ function App() {
|
|
|
77
83
|
<Route
|
|
78
84
|
path="/*"
|
|
79
85
|
element={
|
|
80
|
-
<ProtectedRoute
|
|
86
|
+
<ProtectedRoute
|
|
87
|
+
auth={auth}
|
|
88
|
+
onUnauthorized={() => navigate("/sign-in", { replace: true })}
|
|
89
|
+
>
|
|
81
90
|
<YourApp />
|
|
82
91
|
</ProtectedRoute>
|
|
83
92
|
}
|
|
@@ -92,17 +101,25 @@ function App() {
|
|
|
92
101
|
|
|
93
102
|
```typescript
|
|
94
103
|
import { SignInPage } from "@choiceform/shared-auth"
|
|
104
|
+
import { useNavigate } from "react-router"
|
|
95
105
|
import { auth } from "./lib/auth"
|
|
96
106
|
|
|
97
107
|
function LoginPage() {
|
|
108
|
+
const navigate = useNavigate()
|
|
109
|
+
|
|
98
110
|
return (
|
|
99
111
|
<SignInPage
|
|
100
112
|
auth={auth}
|
|
101
|
-
logo={<YourLogo />}
|
|
102
113
|
title="Your App Title"
|
|
103
114
|
description="Your app description"
|
|
104
115
|
provider="github"
|
|
105
|
-
|
|
116
|
+
redirectUrl="/dashboard"
|
|
117
|
+
onAuthSuccess={() => navigate("/dashboard")}
|
|
118
|
+
githubButton={(isSigningIn) => (
|
|
119
|
+
<button disabled={isSigningIn}>
|
|
120
|
+
{isSigningIn ? "Redirecting to GitHub..." : "Sign in with GitHub"}
|
|
121
|
+
</button>
|
|
122
|
+
)}
|
|
106
123
|
/>
|
|
107
124
|
)
|
|
108
125
|
}
|
|
@@ -118,9 +135,9 @@ function LoginPage() {
|
|
|
118
135
|
|
|
119
136
|
- `baseURL`: Better Auth API 基础 URL(必需)
|
|
120
137
|
- `tokenStorageKey?`: Token 存储的 localStorage key(默认: `'auth-token'`)
|
|
121
|
-
- `
|
|
122
|
-
- `
|
|
123
|
-
-
|
|
138
|
+
- `plugins?`: Better Auth 插件列表(默认包含 `organizationClient()`)
|
|
139
|
+
- ~~`defaultRedirectAfterLogin?`~~: (已废弃) 建议在 SignInPage 组件中通过 `redirectUrl` prop 传入
|
|
140
|
+
- ~~`signInPath?`~~: (已废弃) 建议在 ProtectedRoute 组件中通过 `onUnauthorized` 回调处理导航
|
|
124
141
|
|
|
125
142
|
**返回:** `AuthInstance`
|
|
126
143
|
|
|
@@ -132,11 +149,11 @@ function LoginPage() {
|
|
|
132
149
|
|
|
133
150
|
- `baseURL`: Better Auth API 基础 URL(必需)
|
|
134
151
|
- `tokenStorageKey?`: Token 存储的 localStorage key(默认: `'auth-token'`)
|
|
135
|
-
- `defaultRedirectAfterLogin?`: 登录后默认跳转地址(默认: `'/explore'`)
|
|
136
|
-
- `signInPath?`: 登录页面路径(默认: `'/sign-in'`)
|
|
137
152
|
- `plugins?`: Better Auth 插件列表
|
|
138
153
|
- `callbackURLBuilder?`: 自定义回调 URL 构建函数
|
|
139
154
|
- `getSessionEndpoint?`: 获取 session 的端点路径(默认: `'/v1/auth/get-session'`)
|
|
155
|
+
- ~~`defaultRedirectAfterLogin?`~~: (已废弃) 建议在 SignInPage 组件中通过 `redirectUrl` prop 传入
|
|
156
|
+
- ~~`signInPath?`~~: (已废弃) 建议在 ProtectedRoute 组件中通过 `onUnauthorized` 回调处理导航
|
|
140
157
|
|
|
141
158
|
**返回:** `AuthInstance`
|
|
142
159
|
|
|
@@ -190,9 +207,9 @@ Better Auth 认证状态同步组件。
|
|
|
190
207
|
|
|
191
208
|
- `auth`: AuthInstance
|
|
192
209
|
- `children`: React.ReactNode
|
|
193
|
-
- `
|
|
194
|
-
- `loadingComponent?`:
|
|
195
|
-
- `loadingMessage?`: 加载中消息(默认: `'Checking authentication...'`)
|
|
210
|
+
- `onUnauthorized`: () => void - 当用户未认证时的回调函数(用于导航到登录页)
|
|
211
|
+
- `loadingComponent?`: React.ComponentType<{ message?: string }> - 自定义加载组件
|
|
212
|
+
- `loadingMessage?`: string - 加载中消息(默认: `'Checking authentication...'`)
|
|
196
213
|
|
|
197
214
|
### `SignInPage`
|
|
198
215
|
|
|
@@ -201,15 +218,16 @@ Better Auth 认证状态同步组件。
|
|
|
201
218
|
**Props:**
|
|
202
219
|
|
|
203
220
|
- `auth`: AuthInstance
|
|
204
|
-
- `className?`: 自定义样式类名
|
|
205
|
-
- `
|
|
206
|
-
- `
|
|
207
|
-
- `
|
|
208
|
-
- `
|
|
209
|
-
- `
|
|
210
|
-
- `
|
|
211
|
-
- `
|
|
212
|
-
- `
|
|
221
|
+
- `className?`: string - 自定义样式类名
|
|
222
|
+
- `title?`: string - 标题
|
|
223
|
+
- `description?`: string - 描述
|
|
224
|
+
- `provider?`: string - OAuth 提供商(默认: `'github'`)
|
|
225
|
+
- `redirectUrl?`: string - OAuth 回调重定向地址(默认: `'/explore'`)
|
|
226
|
+
- `onAuthSuccess?`: () => void - 认证成功后的回调函数(用于导航)
|
|
227
|
+
- `githubButton?`: (isSigningIn: boolean) => React.ReactNode - 自定义 GitHub 登录按钮渲染函数
|
|
228
|
+
- `beforeElement?`: React.ReactNode - 在登录表单之前渲染的元素
|
|
229
|
+
- `afterElement?`: React.ReactNode - 在登录表单之后渲染的元素
|
|
230
|
+
- `footerText?`: React.ReactNode - 页脚文本
|
|
213
231
|
|
|
214
232
|
## 工具函数
|
|
215
233
|
|
|
@@ -440,13 +458,17 @@ try {
|
|
|
440
458
|
|
|
441
459
|
### 5. 退出登录
|
|
442
460
|
|
|
443
|
-
退出登录时使用 `signOut`
|
|
461
|
+
退出登录时使用 `signOut` 方法,可以选择性地传入重定向地址:
|
|
444
462
|
|
|
445
463
|
```typescript
|
|
446
464
|
async function handleSignOut() {
|
|
447
465
|
try {
|
|
448
|
-
|
|
449
|
-
|
|
466
|
+
// 传入重定向地址,登出后会自动跳转
|
|
467
|
+
await auth.authActions.signOut("/sign-in")
|
|
468
|
+
|
|
469
|
+
// 或者不传入地址,由调用方手动处理后续导航
|
|
470
|
+
// await auth.authActions.signOut()
|
|
471
|
+
// navigate("/sign-in")
|
|
450
472
|
} catch (error) {
|
|
451
473
|
console.error("Sign out failed:", error)
|
|
452
474
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protected-route.d.ts","sourceRoot":"","sources":["../../src/components/protected-route.tsx"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"protected-route.d.ts","sourceRoot":"","sources":["../../src/components/protected-route.tsx"],"names":[],"mappings":"AACA,OAAO,KAAoB,MAAM,OAAO,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C,UAAU,mBAAmB;IAC3B,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,gBAAgB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,EAAE,MAAM,IAAI,CAAA;CAC3B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAgCxD,CAAA;AAED,eAAe,cAAc,CAAA"}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { observer } from "@legendapp/state/react";
|
|
3
|
-
import {
|
|
3
|
+
import { useEffect } from "react";
|
|
4
4
|
/**
|
|
5
5
|
* 路由保护组件
|
|
6
6
|
* 等待认证初始化完成,根据认证状态进行路由保护
|
|
7
7
|
*/
|
|
8
|
-
export const ProtectedRoute = observer(({ children, auth,
|
|
8
|
+
export const ProtectedRoute = observer(({ children, auth, loadingComponent, loadingMessage, onUnauthorized }) => {
|
|
9
9
|
const { authStore, authComputed } = auth;
|
|
10
10
|
// 检查各种状态
|
|
11
11
|
const isInitializing = authComputed.isInitializing.get();
|
|
12
12
|
const isAuthenticated = authStore.isAuthenticated.get();
|
|
13
|
+
// 当未认证时调用回调
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!isInitializing && !isAuthenticated) {
|
|
16
|
+
onUnauthorized();
|
|
17
|
+
}
|
|
18
|
+
}, [isInitializing, isAuthenticated, onUnauthorized]);
|
|
13
19
|
// 检查初始化状态
|
|
14
20
|
if (isInitializing) {
|
|
15
21
|
if (loadingComponent) {
|
|
@@ -20,7 +26,7 @@ export const ProtectedRoute = observer(({ children, auth, signInPath = "/sign-in
|
|
|
20
26
|
}
|
|
21
27
|
// 检查认证状态
|
|
22
28
|
if (!isAuthenticated) {
|
|
23
|
-
return
|
|
29
|
+
return null;
|
|
24
30
|
}
|
|
25
31
|
// 所有检查通过,渲染子组件
|
|
26
32
|
return _jsx(_Fragment, { children: children });
|
|
@@ -8,13 +8,14 @@ interface SignInPageProps {
|
|
|
8
8
|
description?: string;
|
|
9
9
|
footerText?: React.ReactNode;
|
|
10
10
|
githubButton?: (isSigningIn: boolean) => React.ReactNode;
|
|
11
|
+
onAuthSuccess?: () => void;
|
|
11
12
|
provider?: string;
|
|
12
|
-
|
|
13
|
+
redirectUrl?: string;
|
|
13
14
|
title?: string;
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* 登录页面组件
|
|
17
18
|
*/
|
|
18
|
-
export declare function SignInPage({ afterElement, auth, beforeElement,
|
|
19
|
+
export declare function SignInPage({ afterElement, auth, beforeElement, onAuthSuccess, redirectUrl, provider, title, description, githubButton, className, footerText, }: SignInPageProps): import("react/jsx-runtime").JSX.Element;
|
|
19
20
|
export {};
|
|
20
21
|
//# sourceMappingURL=sign-in-page.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign-in-page.d.ts","sourceRoot":"","sources":["../../src/components/sign-in-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"sign-in-page.d.ts","sourceRoot":"","sources":["../../src/components/sign-in-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C,UAAU,eAAe;IACvB,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,IAAI,EAAE,YAAY,CAAA;IAClB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,YAAY,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAA;IACxD,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EACzB,YAAY,EACZ,IAAI,EACJ,aAAa,EACb,aAAa,EACb,WAAwB,EACxB,QAAmB,EACnB,KAAK,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,GACX,EAAE,eAAe,2CA+CjB"}
|
|
@@ -2,25 +2,23 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Slot } from "@choiceform/design-system";
|
|
3
3
|
import { use$ } from "@legendapp/state/react";
|
|
4
4
|
import { useEffect, useState } from "react";
|
|
5
|
-
import { useNavigate } from "react-router";
|
|
6
5
|
/**
|
|
7
6
|
* 登录页面组件
|
|
8
7
|
*/
|
|
9
|
-
export function SignInPage({ afterElement, auth, beforeElement,
|
|
10
|
-
const navigate = useNavigate();
|
|
8
|
+
export function SignInPage({ afterElement, auth, beforeElement, onAuthSuccess, redirectUrl = "/explore", provider = "github", title, description, githubButton, className, footerText, }) {
|
|
11
9
|
const { authStore, authActions } = auth;
|
|
12
10
|
const { isAuthenticated, error } = use$(authStore);
|
|
13
11
|
const [isSigningIn, setIsSigningIn] = useState(false);
|
|
14
12
|
useEffect(() => {
|
|
15
|
-
if (isAuthenticated) {
|
|
16
|
-
|
|
13
|
+
if (isAuthenticated && onAuthSuccess) {
|
|
14
|
+
onAuthSuccess();
|
|
17
15
|
}
|
|
18
|
-
}, [isAuthenticated,
|
|
16
|
+
}, [isAuthenticated, onAuthSuccess]);
|
|
19
17
|
const handleSignIn = async () => {
|
|
20
18
|
// 设置本地 loading 状态
|
|
21
19
|
setIsSigningIn(true);
|
|
22
20
|
try {
|
|
23
|
-
await authActions.signIn(provider, `${window.location.origin}${
|
|
21
|
+
await authActions.signIn(provider, `${window.location.origin}${redirectUrl}`);
|
|
24
22
|
// OAuth 会重定向,所以这里的代码可能不会执行
|
|
25
23
|
// loading 状态会在页面刷新后重置
|
|
26
24
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -16,8 +16,10 @@ export interface AuthConfig {
|
|
|
16
16
|
*/
|
|
17
17
|
callbackURLBuilder?: (redirectTo: string, baseURL: string) => string;
|
|
18
18
|
/**
|
|
19
|
-
* OAuth
|
|
20
|
-
*
|
|
19
|
+
* OAuth 重定向后的默认跳转地址(可选)
|
|
20
|
+
* 推荐在组件层面通过 props 传入,而不是在配置中设置
|
|
21
|
+
* @default undefined
|
|
22
|
+
* @deprecated 建议在 SignInPage 组件中通过 redirectUrl prop 传入
|
|
21
23
|
*/
|
|
22
24
|
defaultRedirectAfterLogin?: string;
|
|
23
25
|
/**
|
|
@@ -30,8 +32,10 @@ export interface AuthConfig {
|
|
|
30
32
|
*/
|
|
31
33
|
plugins?: BetterAuthPlugin[];
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
+
* 登录页面的路由路径(可选)
|
|
36
|
+
* 推荐在组件层面通过回调传入,而不是在配置中设置
|
|
37
|
+
* @default undefined
|
|
38
|
+
* @deprecated 建议在 ProtectedRoute 组件中通过 onUnauthorized 回调处理导航
|
|
35
39
|
*/
|
|
36
40
|
signInPath?: string;
|
|
37
41
|
/**
|
|
@@ -43,8 +47,10 @@ export interface AuthConfig {
|
|
|
43
47
|
/**
|
|
44
48
|
* 默认配置
|
|
45
49
|
*/
|
|
46
|
-
export declare const defaultAuthConfig: Required<Omit<AuthConfig, "plugins" | "callbackURLBuilder">> & {
|
|
50
|
+
export declare const defaultAuthConfig: Required<Omit<AuthConfig, "plugins" | "callbackURLBuilder" | "defaultRedirectAfterLogin" | "signInPath">> & {
|
|
47
51
|
callbackURLBuilder: (redirectTo: string, baseURL: string) => string;
|
|
52
|
+
defaultRedirectAfterLogin: undefined;
|
|
48
53
|
plugins: BetterAuthPlugin[];
|
|
54
|
+
signInPath: undefined;
|
|
49
55
|
};
|
|
50
56
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,CACvC,cAAc,4BAA4B,EAAE,WAAW,CACxD,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;IAEpE
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,CACvC,cAAc,4BAA4B,EAAE,WAAW,CACxD,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;IAEpE;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAElC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAE3B;;OAEG;IACH,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAE5B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CACtC,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,oBAAoB,GAAG,2BAA2B,GAAG,YAAY,CAAC,CAChG,GAAG;IACF,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;IACnE,yBAAyB,EAAE,SAAS,CAAA;IACpC,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,UAAU,EAAE,SAAS,CAAA;CAWtB,CAAA"}
|
package/dist/config.js
CHANGED
|
@@ -6,9 +6,9 @@ export const defaultAuthConfig = {
|
|
|
6
6
|
callbackURLBuilder: (redirectTo, baseURL) => {
|
|
7
7
|
return `${baseURL}/v1/auth/redirect?to=${encodeURIComponent(redirectTo)}`;
|
|
8
8
|
},
|
|
9
|
-
defaultRedirectAfterLogin:
|
|
9
|
+
defaultRedirectAfterLogin: undefined,
|
|
10
10
|
getSessionEndpoint: "/v1/auth/get-session",
|
|
11
11
|
plugins: [],
|
|
12
|
-
signInPath:
|
|
12
|
+
signInPath: undefined,
|
|
13
13
|
tokenStorageKey: "auth-token",
|
|
14
14
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-auth-sync.d.ts","sourceRoot":"","sources":["../../src/core/init-auth-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BpE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 同步版本的认证初始化
|
|
3
|
+
* 可以在应用渲染前调用(非 React hook)
|
|
4
|
+
*/
|
|
5
|
+
export async function initAuthSync(auth) {
|
|
6
|
+
const { authActions, tokenStorage } = auth;
|
|
7
|
+
// 检查 URL 中的 token
|
|
8
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
9
|
+
let tokenFromUrl = urlParams.get("token");
|
|
10
|
+
if (tokenFromUrl) {
|
|
11
|
+
if (decodeURIComponent(tokenFromUrl) === tokenFromUrl) {
|
|
12
|
+
tokenFromUrl = encodeURIComponent(tokenFromUrl);
|
|
13
|
+
}
|
|
14
|
+
// 立即清理 URL 中的 token 参数(避免暴露)
|
|
15
|
+
urlParams.delete("token");
|
|
16
|
+
const newUrl = urlParams.toString()
|
|
17
|
+
? `${window.location.pathname}?${urlParams.toString()}`
|
|
18
|
+
: window.location.pathname;
|
|
19
|
+
window.history.replaceState({}, "", newUrl);
|
|
20
|
+
// 使用 token 获取 session
|
|
21
|
+
await authActions.fetchSessionWithToken(tokenFromUrl);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
// 检查 localStorage 中是否有存储的 token
|
|
25
|
+
const storedToken = tokenStorage.get();
|
|
26
|
+
if (storedToken) {
|
|
27
|
+
await authActions.fetchSessionWithToken(storedToken);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// 没有 token,标记为已加载
|
|
31
|
+
await authActions.initialize(null, true);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/core.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export declare function createAuth(config: AuthConfig): {
|
|
|
35
35
|
setLoading(loading: boolean): void;
|
|
36
36
|
setError(error: string | null): void;
|
|
37
37
|
signIn(provider?: string, redirectTo?: string): Promise<void>;
|
|
38
|
-
signOut(): Promise<void>;
|
|
38
|
+
signOut(redirectTo?: string): Promise<void>;
|
|
39
39
|
updateUser(user: import("./types").SessionUser | null): void;
|
|
40
40
|
getUser(): import("./types").SessionUser | null;
|
|
41
41
|
};
|
package/dist/init.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import type { AuthConfig } from "./config";
|
|
2
2
|
/**
|
|
3
3
|
* 快速初始化认证系统(使用默认配置)
|
|
4
|
+
*
|
|
5
|
+
* 默认配置:
|
|
6
|
+
* - 使用 organizationClient 插件(支持团队功能)
|
|
7
|
+
* - 如果用户传入自定义 plugins,则使用用户配置(不会合并默认插件)
|
|
8
|
+
*
|
|
9
|
+
* @param config - 认证配置
|
|
10
|
+
* @param config.baseURL - Better Auth API 基础 URL
|
|
11
|
+
* @param config.plugins - Better Auth 插件列表,如果不传则使用默认的 organizationClient
|
|
12
|
+
* @param config.tokenStorageKey - Token 存储的 localStorage key,默认为 "auth-token"
|
|
13
|
+
* @param config.defaultRedirectAfterLogin - (已废弃) 建议在 SignInPage 组件中通过 redirectUrl prop 传入
|
|
14
|
+
* @param config.signInPath - (已废弃) 建议在 ProtectedRoute 组件中通过 onUnauthorized 回调处理导航
|
|
4
15
|
*/
|
|
5
16
|
export declare function initAuth(config: {
|
|
6
17
|
baseURL: string;
|
|
18
|
+
/** @deprecated 建议在 SignInPage 组件中通过 redirectUrl prop 传入 */
|
|
7
19
|
defaultRedirectAfterLogin?: string;
|
|
8
20
|
plugins?: AuthConfig["plugins"];
|
|
21
|
+
/** @deprecated 建议在 ProtectedRoute 组件中通过 onUnauthorized 回调处理导航 */
|
|
9
22
|
signInPath?: string;
|
|
10
23
|
tokenStorageKey?: string;
|
|
11
24
|
}): {
|
|
@@ -41,7 +54,7 @@ export declare function initAuth(config: {
|
|
|
41
54
|
setLoading(loading: boolean): void;
|
|
42
55
|
setError(error: string | null): void;
|
|
43
56
|
signIn(provider?: string, redirectTo?: string): Promise<void>;
|
|
44
|
-
signOut(): Promise<void>;
|
|
57
|
+
signOut(redirectTo?: string): Promise<void>;
|
|
45
58
|
updateUser(user: import("./types").SessionUser | null): void;
|
|
46
59
|
getUser(): import("./types").SessionUser | null;
|
|
47
60
|
};
|
package/dist/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAG1C
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
package/dist/init.js
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { createAuth } from "./core";
|
|
2
|
-
import {
|
|
2
|
+
import { organizationClient } from "better-auth/client/plugins";
|
|
3
3
|
/**
|
|
4
4
|
* 快速初始化认证系统(使用默认配置)
|
|
5
|
+
*
|
|
6
|
+
* 默认配置:
|
|
7
|
+
* - 使用 organizationClient 插件(支持团队功能)
|
|
8
|
+
* - 如果用户传入自定义 plugins,则使用用户配置(不会合并默认插件)
|
|
9
|
+
*
|
|
10
|
+
* @param config - 认证配置
|
|
11
|
+
* @param config.baseURL - Better Auth API 基础 URL
|
|
12
|
+
* @param config.plugins - Better Auth 插件列表,如果不传则使用默认的 organizationClient
|
|
13
|
+
* @param config.tokenStorageKey - Token 存储的 localStorage key,默认为 "auth-token"
|
|
14
|
+
* @param config.defaultRedirectAfterLogin - (已废弃) 建议在 SignInPage 组件中通过 redirectUrl prop 传入
|
|
15
|
+
* @param config.signInPath - (已废弃) 建议在 ProtectedRoute 组件中通过 onUnauthorized 回调处理导航
|
|
5
16
|
*/
|
|
6
17
|
export function initAuth(config) {
|
|
7
18
|
const { baseURL, tokenStorageKey, defaultRedirectAfterLogin, signInPath, plugins } = config;
|
|
8
|
-
// 默认使用
|
|
9
|
-
|
|
19
|
+
// 默认使用 organizationClient(支持团队功能)
|
|
20
|
+
// 如果用户传入了 plugins,则使用用户配置(不合并默认插件)
|
|
21
|
+
const finalPlugins = plugins ?? [organizationClient({ teams: { enabled: true } })];
|
|
10
22
|
return createAuth({
|
|
11
23
|
baseURL,
|
|
12
|
-
plugins:
|
|
24
|
+
plugins: finalPlugins,
|
|
13
25
|
tokenStorageKey: tokenStorageKey || "auth-token",
|
|
14
|
-
defaultRedirectAfterLogin
|
|
15
|
-
signInPath
|
|
26
|
+
defaultRedirectAfterLogin,
|
|
27
|
+
signInPath,
|
|
16
28
|
});
|
|
17
29
|
}
|
package/dist/store/actions.d.ts
CHANGED
|
@@ -53,8 +53,10 @@ export declare function createAuthActions(authStore: Observable<AuthState>, toke
|
|
|
53
53
|
signIn(provider?: string, redirectTo?: string): Promise<void>;
|
|
54
54
|
/**
|
|
55
55
|
* 登出
|
|
56
|
+
*
|
|
57
|
+
* @param redirectTo 登出后的重定向地址(可选),如果不提供则不执行自动跳转
|
|
56
58
|
*/
|
|
57
|
-
signOut(): Promise<void>;
|
|
59
|
+
signOut(redirectTo?: string): Promise<void>;
|
|
58
60
|
/**
|
|
59
61
|
* 更新用户信息
|
|
60
62
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAgE3C;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,EAChC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE;IACV,MAAM,EAAE;QACN,MAAM,EAAE,CAAC,OAAO,EAAE;YAAE,WAAW,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;KACjF,CAAA;IACD,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAChC;
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAgE3C;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,EAChC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE;IACV,MAAM,EAAE;QACN,MAAM,EAAE,CAAC,OAAO,EAAE;YAAE,WAAW,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;KACjF,CAAA;IACD,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAChC;IAcC;;OAEG;qBACoB,WAAW,GAAG,IAAI,YAAY,OAAO;IAe5D;;;;;;;;;;OAUG;iCACgC,MAAM;IAuDzC;;;OAGG;;IASH;;OAEG;wBACiB,OAAO;IAI3B;;OAEG;oBACa,MAAM,GAAG,IAAI;IAI7B;;;;;;OAMG;sBACoB,MAAM,eAA0B,MAAM;IAqC7D;;;;OAIG;yBACwB,MAAM;IAiCjC;;OAEG;qBACc,WAAW,GAAG,IAAI;IAUnC;;OAEG;eACQ,WAAW,GAAG,IAAI;EAIhC;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
|
package/dist/store/actions.js
CHANGED
|
@@ -58,7 +58,7 @@ function extractUserData(sessionData) {
|
|
|
58
58
|
* 创建认证 actions
|
|
59
59
|
*/
|
|
60
60
|
export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
61
|
-
const { baseURL, defaultRedirectAfterLogin
|
|
61
|
+
const { baseURL, defaultRedirectAfterLogin, getSessionEndpoint = "/v1/auth/get-session", callbackURLBuilder, } = config;
|
|
62
62
|
const buildCallbackURL = callbackURLBuilder || ((redirectTo, baseURL) => {
|
|
63
63
|
return `${baseURL}/v1/auth/redirect?to=${encodeURIComponent(redirectTo)}`;
|
|
64
64
|
});
|
|
@@ -149,6 +149,8 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
149
149
|
handleUnauthorized() {
|
|
150
150
|
authStore.user.set(null);
|
|
151
151
|
authStore.isAuthenticated.set(false);
|
|
152
|
+
authStore.isLoaded.set(true);
|
|
153
|
+
authStore.loading.set(false);
|
|
152
154
|
tokenStorage.clear();
|
|
153
155
|
},
|
|
154
156
|
/**
|
|
@@ -186,7 +188,9 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
186
188
|
? redirectTo.startsWith("http")
|
|
187
189
|
? redirectTo
|
|
188
190
|
: `${window.location.origin}${redirectTo}`
|
|
189
|
-
:
|
|
191
|
+
: defaultRedirectAfterLogin
|
|
192
|
+
? `${window.location.origin}${defaultRedirectAfterLogin}`
|
|
193
|
+
: `${window.location.origin}/explore`;
|
|
190
194
|
const callbackURL = buildCallbackURL(finalRedirectTo, baseURL);
|
|
191
195
|
await authClient.signIn.social({
|
|
192
196
|
provider,
|
|
@@ -202,8 +206,10 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
202
206
|
},
|
|
203
207
|
/**
|
|
204
208
|
* 登出
|
|
209
|
+
*
|
|
210
|
+
* @param redirectTo 登出后的重定向地址(可选),如果不提供则不执行自动跳转
|
|
205
211
|
*/
|
|
206
|
-
async signOut() {
|
|
212
|
+
async signOut(redirectTo) {
|
|
207
213
|
// 防止重复调用
|
|
208
214
|
if (authStore.loading.get()) {
|
|
209
215
|
return;
|
|
@@ -216,8 +222,10 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
216
222
|
authStore.user.set(null);
|
|
217
223
|
authStore.isAuthenticated.set(false);
|
|
218
224
|
tokenStorage.clear();
|
|
219
|
-
//
|
|
220
|
-
|
|
225
|
+
// 如果提供了重定向地址,则执行跳转
|
|
226
|
+
if (redirectTo) {
|
|
227
|
+
window.location.href = redirectTo;
|
|
228
|
+
}
|
|
221
229
|
}
|
|
222
230
|
catch (error) {
|
|
223
231
|
const message = error instanceof Error ? error.message : "Sign out failed";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@choiceform/shared-auth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Shared authentication package for Choiceform projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
"dist",
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"dev": "tsc --watch",
|
|
22
|
+
"clean": "rimraf dist",
|
|
23
|
+
"prepublishOnly": "pnpm run build"
|
|
24
|
+
},
|
|
19
25
|
"repository": {
|
|
20
26
|
"type": "git",
|
|
21
27
|
"url": "git+https://github.com/choiceform/automation.git",
|
|
@@ -43,18 +49,12 @@
|
|
|
43
49
|
"@legendapp/state": "v3.0.0-beta.26",
|
|
44
50
|
"better-auth": "^1.3.8",
|
|
45
51
|
"react": ">=18.0.0",
|
|
46
|
-
"react-dom": ">=18.0.0"
|
|
47
|
-
"react-router": "^7.6.3"
|
|
52
|
+
"react-dom": ">=18.0.0"
|
|
48
53
|
},
|
|
49
54
|
"devDependencies": {
|
|
50
55
|
"@types/react": "18.2.71",
|
|
51
56
|
"@types/react-dom": "18.2.22",
|
|
52
57
|
"typescript": "^5.5.3",
|
|
53
58
|
"rimraf": "^6.0.1"
|
|
54
|
-
},
|
|
55
|
-
"scripts": {
|
|
56
|
-
"build": "tsc",
|
|
57
|
-
"dev": "tsc --watch",
|
|
58
|
-
"clean": "rimraf dist"
|
|
59
59
|
}
|
|
60
|
-
}
|
|
60
|
+
}
|
package/LICENSE.md
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# License
|
|
2
|
-
|
|
3
|
-
Portions of this software are licensed as follows:
|
|
4
|
-
|
|
5
|
-
- Content of branches other than the main branch are not licensed.
|
|
6
|
-
- Source code files that contain `.ee.` in their filename or `.ee` in their directory name are NOT licensed under the Sustainable Use License. To use source code files that contain `.ee.` in their filename or `.ee` in their directory name you must hold a valid Rungraf Enterprise License specifically allowing you access to such source code files and as defined in "LICENSE_EE.md".
|
|
7
|
-
- All third party components incorporated into the Rungraf software are licensed under the original license provided by the owner of the applicable component.
|
|
8
|
-
- Content outside of the above mentioned files or restrictions is available under the "Sustainable Use License" as defined below.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Sustainable Use License
|
|
13
|
-
|
|
14
|
-
**Version 1.0**
|
|
15
|
-
|
|
16
|
-
### Acceptance
|
|
17
|
-
|
|
18
|
-
By using the software, you agree to all of the terms and conditions below.
|
|
19
|
-
|
|
20
|
-
### Copyright License
|
|
21
|
-
|
|
22
|
-
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
|
|
23
|
-
|
|
24
|
-
### Limitations
|
|
25
|
-
|
|
26
|
-
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor's trademarks is subject to applicable law.
|
|
27
|
-
|
|
28
|
-
### Patents
|
|
29
|
-
|
|
30
|
-
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
31
|
-
|
|
32
|
-
### Notices
|
|
33
|
-
|
|
34
|
-
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
|
|
35
|
-
|
|
36
|
-
### No Other Rights
|
|
37
|
-
|
|
38
|
-
These terms do not imply any licenses other than those expressly granted in these terms.
|
|
39
|
-
|
|
40
|
-
### Termination
|
|
41
|
-
|
|
42
|
-
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
|
|
43
|
-
|
|
44
|
-
### No Liability
|
|
45
|
-
|
|
46
|
-
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
|
47
|
-
|
|
48
|
-
### Definitions
|
|
49
|
-
|
|
50
|
-
- The **"licensor"** is the entity offering these terms, which is the Rungraf project and its contributors.
|
|
51
|
-
|
|
52
|
-
- The **"software"** is the software the licensor makes available under these terms, including any portion of it.
|
|
53
|
-
|
|
54
|
-
- **"You"** refers to the individual or entity agreeing to these terms.
|
|
55
|
-
|
|
56
|
-
- **"Your company"** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
57
|
-
|
|
58
|
-
- **"Your license"** is the license granted to you for the software under these terms.
|
|
59
|
-
|
|
60
|
-
- **"Use"** means anything you do with the software requiring your license.
|
|
61
|
-
|
|
62
|
-
- **"Trademark"** means trademarks, service marks, and similar rights.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Additional Terms for Rungraf
|
|
67
|
-
|
|
68
|
-
In addition to the Sustainable Use License terms above, the following specific limitations apply to Rungraf:
|
|
69
|
-
|
|
70
|
-
### Multi-Tenant SaaS Restriction
|
|
71
|
-
|
|
72
|
-
You may NOT use Rungraf to operate a multi-tenant Software-as-a-Service (SaaS) offering where you provide Rungraf as a hosted service to multiple external customers or organizations, unless you obtain a separate commercial license from the Rungraf project.
|
|
73
|
-
|
|
74
|
-
**Examples of PROHIBITED use without commercial license:**
|
|
75
|
-
- Operating "AI Agent Platform as a Service" for multiple paying customers
|
|
76
|
-
- Providing Rungraf as a white-labeled workflow automation service
|
|
77
|
-
- Running a marketplace where multiple organizations build AI Agents on your hosted Rungraf instance
|
|
78
|
-
|
|
79
|
-
**Examples of PERMITTED use:**
|
|
80
|
-
- Deploying Rungraf within your organization for your employees and internal use
|
|
81
|
-
- Embedding Rungraf in your product where each customer gets their own dedicated Rungraf instance
|
|
82
|
-
- Using Rungraf as a backend service for your own application (single-tenant)
|
|
83
|
-
|
|
84
|
-
**Workspace Definition:** Within Rungraf, one workspace represents one tenant. A workspace provides an isolated environment for each tenant's AI Agents, workflows, data, and configurations.
|
|
85
|
-
|
|
86
|
-
### Branding and Attribution
|
|
87
|
-
|
|
88
|
-
When using Rungraf's frontend interface, you may not remove, alter, or obscure the Rungraf logo, branding, or copyright notices displayed in the user interface. This restriction applies only to the visual frontend components.
|
|
89
|
-
|
|
90
|
-
**Frontend Definition:** The "frontend" of Rungraf includes all components located in the `packages/client/` directory when running from source code, or the "client" Docker image when running via containers.
|
|
91
|
-
|
|
92
|
-
**Examples of PERMITTED use:**
|
|
93
|
-
- Using only Rungraf's backend APIs with your own custom frontend (no branding requirement)
|
|
94
|
-
- Forking and customizing the codebase while maintaining attribution
|
|
95
|
-
- White-labeling with a separate commercial license
|
|
96
|
-
|
|
97
|
-
**Examples of PROHIBITED use:**
|
|
98
|
-
- Using the Rungraf frontend with logos and branding removed
|
|
99
|
-
- Distributing modified versions without proper attribution
|
|
100
|
-
|
|
101
|
-
### Core Engine Protection
|
|
102
|
-
|
|
103
|
-
The Rungraf AI Agent Runtime (located in `packages/runner/`) and Expression Engine may be used and modified for your own purposes, but you may NOT:
|
|
104
|
-
|
|
105
|
-
- Extract the Agent Runtime as a standalone product and sell it separately
|
|
106
|
-
- Use Rungraf's core orchestration engine to build a competing workflow automation platform for sale
|
|
107
|
-
- Offer the Expression Engine as a standalone commercial service
|
|
108
|
-
|
|
109
|
-
**Examples of PERMITTED use:**
|
|
110
|
-
- Integrating Rungraf into your product's backend
|
|
111
|
-
- Modifying the runtime for your specific use case
|
|
112
|
-
- Contributing improvements back to the open source project
|
|
113
|
-
|
|
114
|
-
**Examples of PROHIBITED use:**
|
|
115
|
-
- Packaging the Elixir Agent Runtime as "SuperAgent Engine" and selling it
|
|
116
|
-
- Building a competitor workflow platform using Rungraf's core code
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## Fair Code Principles
|
|
121
|
-
|
|
122
|
-
Rungraf follows the [Fair Code](https://faircode.io) principles. We believe in:
|
|
123
|
-
|
|
124
|
-
1. **Transparency**: Source code is publicly available for review and contribution
|
|
125
|
-
2. **Sustainability**: Protecting the project's ability to fund ongoing development
|
|
126
|
-
3. **Community**: Encouraging contributions while preventing exploitation
|
|
127
|
-
4. **Freedom**: Allowing use for internal business purposes and non-commercial projects
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Getting a Commercial License
|
|
132
|
-
|
|
133
|
-
If your use case falls under the restrictions above, you can obtain a commercial Rungraf Enterprise License. Enterprise licenses include:
|
|
134
|
-
|
|
135
|
-
- Multi-tenant SaaS deployment rights
|
|
136
|
-
- White-labeling permissions
|
|
137
|
-
- Priority support and SLA guarantees
|
|
138
|
-
- Enterprise features (SSO, advanced RBAC, audit logs)
|
|
139
|
-
- Custom development support
|
|
140
|
-
|
|
141
|
-
Contact us for enterprise licensing:
|
|
142
|
-
- **Email**: [enterprise@rungraf.io](mailto:enterprise@rungraf.io)
|
|
143
|
-
- **Website**: [https://rungraf.io/enterprise](https://rungraf.io/enterprise)
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
**© 2024-2025 Rungraf Project**
|
|
148
|
-
|
|
149
|
-
This software is provided "as is", without warranty of any kind, express or implied.
|