@feelflow/ffid-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -0
- package/dist/chunk-A63MX52D.js +861 -0
- package/dist/chunk-YCMQXJOS.cjs +872 -0
- package/dist/components/index.cjs +22 -0
- package/dist/components/index.d.cts +3 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +1 -0
- package/dist/index-CtBBLbTn.d.cts +322 -0
- package/dist/index-CtBBLbTn.d.ts +322 -0
- package/dist/index.cjs +68 -0
- package/dist/index.d.cts +181 -0
- package/dist/index.d.ts +181 -0
- package/dist/index.js +31 -0
- package/dist/legal/index.cjs +180 -0
- package/dist/legal/index.d.cts +332 -0
- package/dist/legal/index.d.ts +332 -0
- package/dist/legal/index.js +176 -0
- package/package.json +84 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkYCMQXJOS_cjs = require('./chunk-YCMQXJOS.cjs');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
function withFFIDAuth(Component, options = {}) {
|
|
8
|
+
const WrappedComponent = (props) => {
|
|
9
|
+
const { isLoading, isAuthenticated, login } = chunkYCMQXJOS_cjs.useFFIDContext();
|
|
10
|
+
const hasRedirected = react.useRef(false);
|
|
11
|
+
react.useEffect(() => {
|
|
12
|
+
if (!isLoading && !isAuthenticated && options.redirectToLogin && !hasRedirected.current) {
|
|
13
|
+
hasRedirected.current = true;
|
|
14
|
+
login();
|
|
15
|
+
}
|
|
16
|
+
}, [isLoading, isAuthenticated, login]);
|
|
17
|
+
if (isLoading) {
|
|
18
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: options.loading ?? null });
|
|
19
|
+
}
|
|
20
|
+
if (!isAuthenticated) {
|
|
21
|
+
if (options.redirectToLogin) {
|
|
22
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: options.loading ?? null });
|
|
23
|
+
}
|
|
24
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: options.fallback ?? null });
|
|
25
|
+
}
|
|
26
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props });
|
|
27
|
+
};
|
|
28
|
+
WrappedComponent.displayName = `withFFIDAuth(${Component.displayName ?? Component.name ?? "Component"})`;
|
|
29
|
+
return WrappedComponent;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () { return chunkYCMQXJOS_cjs.DEFAULT_API_BASE_URL; }
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () { return chunkYCMQXJOS_cjs.FFIDLoginButton; }
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
get: function () { return chunkYCMQXJOS_cjs.FFIDOrganizationSwitcher; }
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(exports, "FFIDProvider", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
get: function () { return chunkYCMQXJOS_cjs.FFIDProvider; }
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function () { return chunkYCMQXJOS_cjs.FFIDSubscriptionBadge; }
|
|
51
|
+
});
|
|
52
|
+
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: function () { return chunkYCMQXJOS_cjs.FFIDUserMenu; }
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(exports, "useFFID", {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
get: function () { return chunkYCMQXJOS_cjs.useFFID; }
|
|
59
|
+
});
|
|
60
|
+
Object.defineProperty(exports, "useSubscription", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
get: function () { return chunkYCMQXJOS_cjs.useSubscription; }
|
|
63
|
+
});
|
|
64
|
+
Object.defineProperty(exports, "withSubscription", {
|
|
65
|
+
enumerable: true,
|
|
66
|
+
get: function () { return chunkYCMQXJOS_cjs.withSubscription; }
|
|
67
|
+
});
|
|
68
|
+
exports.withFFIDAuth = withFFIDAuth;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, ComponentType, FC } from 'react';
|
|
3
|
+
import { F as FFIDConfig, a as FFIDUser, b as FFIDOrganization, c as FFIDError, d as FFIDSubscriptionContextValue } from './index-CtBBLbTn.cjs';
|
|
4
|
+
export { e as FFIDApiResponse, f as FFIDContextValue, g as FFIDLogger, h as FFIDLoginButton, i as FFIDOrganizationSwitcher, j as FFIDSessionResponse, k as FFIDSubscription, l as FFIDSubscriptionBadge, m as FFIDUserMenu } from './index-CtBBLbTn.cjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* FFID SDK Shared Constants
|
|
8
|
+
*
|
|
9
|
+
* Constants shared across all SDK entry points (main client + legal client).
|
|
10
|
+
* Centralizing these prevents drift during domain/URL changes.
|
|
11
|
+
*/
|
|
12
|
+
/** Default FFID API base URL (production) */
|
|
13
|
+
declare const DEFAULT_API_BASE_URL = "https://id.feelflow.co.jp";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Props for FFIDProvider component
|
|
17
|
+
*/
|
|
18
|
+
interface FFIDProviderProps extends FFIDConfig {
|
|
19
|
+
/** Child components */
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* FFIDProvider - Wrap your app to enable FFID authentication
|
|
24
|
+
*
|
|
25
|
+
* This provider handles:
|
|
26
|
+
* - Session management
|
|
27
|
+
* - User authentication state
|
|
28
|
+
* - Organization switching
|
|
29
|
+
* - Automatic session refresh
|
|
30
|
+
*/
|
|
31
|
+
declare function FFIDProvider({ children, serviceCode, apiBaseUrl, debug, logger, refreshInterval, onAuthStateChange, onError, }: FFIDProviderProps): react_jsx_runtime.JSX.Element;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Return type for useFFID hook
|
|
35
|
+
*/
|
|
36
|
+
interface UseFFIDReturn {
|
|
37
|
+
/** Current authenticated user (null if not logged in) */
|
|
38
|
+
user: FFIDUser | null;
|
|
39
|
+
/** List of user's organizations */
|
|
40
|
+
organizations: FFIDOrganization[];
|
|
41
|
+
/** Currently selected organization */
|
|
42
|
+
currentOrganization: FFIDOrganization | null;
|
|
43
|
+
/** Whether session is being loaded */
|
|
44
|
+
isLoading: boolean;
|
|
45
|
+
/** Whether user is authenticated */
|
|
46
|
+
isAuthenticated: boolean;
|
|
47
|
+
/** Any authentication error that occurred */
|
|
48
|
+
error: FFIDError | null;
|
|
49
|
+
/** Redirect to login page */
|
|
50
|
+
login: () => void;
|
|
51
|
+
/** Sign out */
|
|
52
|
+
logout: () => Promise<void>;
|
|
53
|
+
/** Switch current organization */
|
|
54
|
+
switchOrganization: (organizationId: string) => void;
|
|
55
|
+
/** Refresh session data */
|
|
56
|
+
refresh: () => Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Hook to access FFID authentication and user data
|
|
60
|
+
*
|
|
61
|
+
* Must be used within FFIDProvider
|
|
62
|
+
*/
|
|
63
|
+
declare function useFFID(): UseFFIDReturn;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* useSubscription Hook
|
|
67
|
+
*
|
|
68
|
+
* Access subscription/contract information for the current service
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```tsx
|
|
72
|
+
* import { useSubscription } from '@feelflow/ffid-sdk'
|
|
73
|
+
*
|
|
74
|
+
* function PremiumFeature() {
|
|
75
|
+
* const { isActive, hasPlan, planCode } = useSubscription()
|
|
76
|
+
*
|
|
77
|
+
* if (!isActive) {
|
|
78
|
+
* return <div>契約が必要です</div>
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* if (!hasPlan(['pro', 'enterprise'])) {
|
|
82
|
+
* return <div>プロプラン以上が必要です</div>
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* return <div>Premium Content</div>
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Hook to access subscription information
|
|
92
|
+
*
|
|
93
|
+
* Must be used within FFIDProvider
|
|
94
|
+
*/
|
|
95
|
+
declare function useSubscription(): FFIDSubscriptionContextValue;
|
|
96
|
+
/**
|
|
97
|
+
* HOC to require subscription for a component
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* import { withSubscription } from '@feelflow/ffid-sdk'
|
|
102
|
+
*
|
|
103
|
+
* const PremiumDashboard = withSubscription(Dashboard, {
|
|
104
|
+
* plans: ['pro', 'enterprise'],
|
|
105
|
+
* fallback: <UpgradePrompt />,
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
interface WithSubscriptionOptions {
|
|
110
|
+
/** Required plans (any of these) */
|
|
111
|
+
plans?: string[];
|
|
112
|
+
/** Component to show when subscription check fails */
|
|
113
|
+
fallback?: ReactNode;
|
|
114
|
+
/** Component to show while loading */
|
|
115
|
+
loading?: ReactNode;
|
|
116
|
+
}
|
|
117
|
+
declare function withSubscription<P extends object>(Component: ComponentType<P>, options?: WithSubscriptionOptions): FC<P>;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* withFFIDAuth HOC
|
|
121
|
+
*
|
|
122
|
+
* Wrap a component to require FFID authentication.
|
|
123
|
+
* Renders the wrapped component only when the user is authenticated.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```tsx
|
|
127
|
+
* import { withFFIDAuth } from '@feelflow/ffid-sdk'
|
|
128
|
+
*
|
|
129
|
+
* function Dashboard() {
|
|
130
|
+
* return <div>Protected Dashboard</div>
|
|
131
|
+
* }
|
|
132
|
+
*
|
|
133
|
+
* // Basic usage - renders nothing when not authenticated
|
|
134
|
+
* export default withFFIDAuth(Dashboard)
|
|
135
|
+
*
|
|
136
|
+
* // With redirect to login
|
|
137
|
+
* export default withFFIDAuth(Dashboard, {
|
|
138
|
+
* redirectToLogin: true,
|
|
139
|
+
* loading: <div>認証確認中...</div>,
|
|
140
|
+
* })
|
|
141
|
+
*
|
|
142
|
+
* // With fallback component
|
|
143
|
+
* export default withFFIDAuth(Dashboard, {
|
|
144
|
+
* fallback: <div>ログインが必要です</div>,
|
|
145
|
+
* })
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Options for withFFIDAuth HOC
|
|
151
|
+
*/
|
|
152
|
+
interface WithFFIDAuthOptions {
|
|
153
|
+
/** Automatically redirect to FFID login page when not authenticated (default: false) */
|
|
154
|
+
redirectToLogin?: boolean;
|
|
155
|
+
/** Component to show while authentication is being checked */
|
|
156
|
+
loading?: ReactNode;
|
|
157
|
+
/** Component to show when user is not authenticated (ignored if redirectToLogin is true) */
|
|
158
|
+
fallback?: ReactNode;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* HOC to require FFID authentication for a component
|
|
162
|
+
*
|
|
163
|
+
* Renders the wrapped component only when the user is authenticated.
|
|
164
|
+
* While authentication is loading, shows the loading component (if provided).
|
|
165
|
+
* When not authenticated, either redirects to login or shows fallback.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* // Redirect to login on unauthenticated
|
|
170
|
+
* const ProtectedPage = withFFIDAuth(MyPage, { redirectToLogin: true })
|
|
171
|
+
*
|
|
172
|
+
* // Show custom fallback
|
|
173
|
+
* const ProtectedPage = withFFIDAuth(MyPage, {
|
|
174
|
+
* fallback: <LoginPrompt />,
|
|
175
|
+
* loading: <Spinner />,
|
|
176
|
+
* })
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
declare function withFFIDAuth<P extends object>(Component: ComponentType<P>, options?: WithFFIDAuthOptions): FC<P>;
|
|
180
|
+
|
|
181
|
+
export { DEFAULT_API_BASE_URL, FFIDConfig, FFIDError, FFIDOrganization, FFIDProvider, type FFIDProviderProps, FFIDSubscriptionContextValue, FFIDUser, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, useFFID, useSubscription, withFFIDAuth, withSubscription };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, ComponentType, FC } from 'react';
|
|
3
|
+
import { F as FFIDConfig, a as FFIDUser, b as FFIDOrganization, c as FFIDError, d as FFIDSubscriptionContextValue } from './index-CtBBLbTn.js';
|
|
4
|
+
export { e as FFIDApiResponse, f as FFIDContextValue, g as FFIDLogger, h as FFIDLoginButton, i as FFIDOrganizationSwitcher, j as FFIDSessionResponse, k as FFIDSubscription, l as FFIDSubscriptionBadge, m as FFIDUserMenu } from './index-CtBBLbTn.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* FFID SDK Shared Constants
|
|
8
|
+
*
|
|
9
|
+
* Constants shared across all SDK entry points (main client + legal client).
|
|
10
|
+
* Centralizing these prevents drift during domain/URL changes.
|
|
11
|
+
*/
|
|
12
|
+
/** Default FFID API base URL (production) */
|
|
13
|
+
declare const DEFAULT_API_BASE_URL = "https://id.feelflow.co.jp";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Props for FFIDProvider component
|
|
17
|
+
*/
|
|
18
|
+
interface FFIDProviderProps extends FFIDConfig {
|
|
19
|
+
/** Child components */
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* FFIDProvider - Wrap your app to enable FFID authentication
|
|
24
|
+
*
|
|
25
|
+
* This provider handles:
|
|
26
|
+
* - Session management
|
|
27
|
+
* - User authentication state
|
|
28
|
+
* - Organization switching
|
|
29
|
+
* - Automatic session refresh
|
|
30
|
+
*/
|
|
31
|
+
declare function FFIDProvider({ children, serviceCode, apiBaseUrl, debug, logger, refreshInterval, onAuthStateChange, onError, }: FFIDProviderProps): react_jsx_runtime.JSX.Element;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Return type for useFFID hook
|
|
35
|
+
*/
|
|
36
|
+
interface UseFFIDReturn {
|
|
37
|
+
/** Current authenticated user (null if not logged in) */
|
|
38
|
+
user: FFIDUser | null;
|
|
39
|
+
/** List of user's organizations */
|
|
40
|
+
organizations: FFIDOrganization[];
|
|
41
|
+
/** Currently selected organization */
|
|
42
|
+
currentOrganization: FFIDOrganization | null;
|
|
43
|
+
/** Whether session is being loaded */
|
|
44
|
+
isLoading: boolean;
|
|
45
|
+
/** Whether user is authenticated */
|
|
46
|
+
isAuthenticated: boolean;
|
|
47
|
+
/** Any authentication error that occurred */
|
|
48
|
+
error: FFIDError | null;
|
|
49
|
+
/** Redirect to login page */
|
|
50
|
+
login: () => void;
|
|
51
|
+
/** Sign out */
|
|
52
|
+
logout: () => Promise<void>;
|
|
53
|
+
/** Switch current organization */
|
|
54
|
+
switchOrganization: (organizationId: string) => void;
|
|
55
|
+
/** Refresh session data */
|
|
56
|
+
refresh: () => Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Hook to access FFID authentication and user data
|
|
60
|
+
*
|
|
61
|
+
* Must be used within FFIDProvider
|
|
62
|
+
*/
|
|
63
|
+
declare function useFFID(): UseFFIDReturn;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* useSubscription Hook
|
|
67
|
+
*
|
|
68
|
+
* Access subscription/contract information for the current service
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```tsx
|
|
72
|
+
* import { useSubscription } from '@feelflow/ffid-sdk'
|
|
73
|
+
*
|
|
74
|
+
* function PremiumFeature() {
|
|
75
|
+
* const { isActive, hasPlan, planCode } = useSubscription()
|
|
76
|
+
*
|
|
77
|
+
* if (!isActive) {
|
|
78
|
+
* return <div>契約が必要です</div>
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* if (!hasPlan(['pro', 'enterprise'])) {
|
|
82
|
+
* return <div>プロプラン以上が必要です</div>
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* return <div>Premium Content</div>
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Hook to access subscription information
|
|
92
|
+
*
|
|
93
|
+
* Must be used within FFIDProvider
|
|
94
|
+
*/
|
|
95
|
+
declare function useSubscription(): FFIDSubscriptionContextValue;
|
|
96
|
+
/**
|
|
97
|
+
* HOC to require subscription for a component
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* import { withSubscription } from '@feelflow/ffid-sdk'
|
|
102
|
+
*
|
|
103
|
+
* const PremiumDashboard = withSubscription(Dashboard, {
|
|
104
|
+
* plans: ['pro', 'enterprise'],
|
|
105
|
+
* fallback: <UpgradePrompt />,
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
interface WithSubscriptionOptions {
|
|
110
|
+
/** Required plans (any of these) */
|
|
111
|
+
plans?: string[];
|
|
112
|
+
/** Component to show when subscription check fails */
|
|
113
|
+
fallback?: ReactNode;
|
|
114
|
+
/** Component to show while loading */
|
|
115
|
+
loading?: ReactNode;
|
|
116
|
+
}
|
|
117
|
+
declare function withSubscription<P extends object>(Component: ComponentType<P>, options?: WithSubscriptionOptions): FC<P>;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* withFFIDAuth HOC
|
|
121
|
+
*
|
|
122
|
+
* Wrap a component to require FFID authentication.
|
|
123
|
+
* Renders the wrapped component only when the user is authenticated.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```tsx
|
|
127
|
+
* import { withFFIDAuth } from '@feelflow/ffid-sdk'
|
|
128
|
+
*
|
|
129
|
+
* function Dashboard() {
|
|
130
|
+
* return <div>Protected Dashboard</div>
|
|
131
|
+
* }
|
|
132
|
+
*
|
|
133
|
+
* // Basic usage - renders nothing when not authenticated
|
|
134
|
+
* export default withFFIDAuth(Dashboard)
|
|
135
|
+
*
|
|
136
|
+
* // With redirect to login
|
|
137
|
+
* export default withFFIDAuth(Dashboard, {
|
|
138
|
+
* redirectToLogin: true,
|
|
139
|
+
* loading: <div>認証確認中...</div>,
|
|
140
|
+
* })
|
|
141
|
+
*
|
|
142
|
+
* // With fallback component
|
|
143
|
+
* export default withFFIDAuth(Dashboard, {
|
|
144
|
+
* fallback: <div>ログインが必要です</div>,
|
|
145
|
+
* })
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Options for withFFIDAuth HOC
|
|
151
|
+
*/
|
|
152
|
+
interface WithFFIDAuthOptions {
|
|
153
|
+
/** Automatically redirect to FFID login page when not authenticated (default: false) */
|
|
154
|
+
redirectToLogin?: boolean;
|
|
155
|
+
/** Component to show while authentication is being checked */
|
|
156
|
+
loading?: ReactNode;
|
|
157
|
+
/** Component to show when user is not authenticated (ignored if redirectToLogin is true) */
|
|
158
|
+
fallback?: ReactNode;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* HOC to require FFID authentication for a component
|
|
162
|
+
*
|
|
163
|
+
* Renders the wrapped component only when the user is authenticated.
|
|
164
|
+
* While authentication is loading, shows the loading component (if provided).
|
|
165
|
+
* When not authenticated, either redirects to login or shows fallback.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* // Redirect to login on unauthenticated
|
|
170
|
+
* const ProtectedPage = withFFIDAuth(MyPage, { redirectToLogin: true })
|
|
171
|
+
*
|
|
172
|
+
* // Show custom fallback
|
|
173
|
+
* const ProtectedPage = withFFIDAuth(MyPage, {
|
|
174
|
+
* fallback: <LoginPrompt />,
|
|
175
|
+
* loading: <Spinner />,
|
|
176
|
+
* })
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
declare function withFFIDAuth<P extends object>(Component: ComponentType<P>, options?: WithFFIDAuthOptions): FC<P>;
|
|
180
|
+
|
|
181
|
+
export { DEFAULT_API_BASE_URL, FFIDConfig, FFIDError, FFIDOrganization, FFIDProvider, type FFIDProviderProps, FFIDSubscriptionContextValue, FFIDUser, type UseFFIDReturn, type WithFFIDAuthOptions, type WithSubscriptionOptions, useFFID, useSubscription, withFFIDAuth, withSubscription };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useFFIDContext } from './chunk-A63MX52D.js';
|
|
2
|
+
export { DEFAULT_API_BASE_URL, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSubscriptionBadge, FFIDUserMenu, useFFID, useSubscription, withSubscription } from './chunk-A63MX52D.js';
|
|
3
|
+
import { useRef, useEffect } from 'react';
|
|
4
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function withFFIDAuth(Component, options = {}) {
|
|
7
|
+
const WrappedComponent = (props) => {
|
|
8
|
+
const { isLoading, isAuthenticated, login } = useFFIDContext();
|
|
9
|
+
const hasRedirected = useRef(false);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!isLoading && !isAuthenticated && options.redirectToLogin && !hasRedirected.current) {
|
|
12
|
+
hasRedirected.current = true;
|
|
13
|
+
login();
|
|
14
|
+
}
|
|
15
|
+
}, [isLoading, isAuthenticated, login]);
|
|
16
|
+
if (isLoading) {
|
|
17
|
+
return /* @__PURE__ */ jsx(Fragment, { children: options.loading ?? null });
|
|
18
|
+
}
|
|
19
|
+
if (!isAuthenticated) {
|
|
20
|
+
if (options.redirectToLogin) {
|
|
21
|
+
return /* @__PURE__ */ jsx(Fragment, { children: options.loading ?? null });
|
|
22
|
+
}
|
|
23
|
+
return /* @__PURE__ */ jsx(Fragment, { children: options.fallback ?? null });
|
|
24
|
+
}
|
|
25
|
+
return /* @__PURE__ */ jsx(Component, { ...props });
|
|
26
|
+
};
|
|
27
|
+
WrappedComponent.displayName = `withFFIDAuth(${Component.displayName ?? Component.name ?? "Component"})`;
|
|
28
|
+
return WrappedComponent;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { withFFIDAuth };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/constants.ts
|
|
4
|
+
var DEFAULT_API_BASE_URL = "https://id.feelflow.co.jp";
|
|
5
|
+
|
|
6
|
+
// src/legal/ffid-legal-client.ts
|
|
7
|
+
var API_PREFIX = "/api/v1/legal/ext";
|
|
8
|
+
var SDK_LOG_PREFIX = "[FFID Legal SDK]";
|
|
9
|
+
var NO_CONTENT_STATUS = 204;
|
|
10
|
+
var FFID_LEGAL_ERROR_CODES = {
|
|
11
|
+
/** API key is missing */
|
|
12
|
+
MISSING_API_KEY: "MISSING_API_KEY",
|
|
13
|
+
/** Network request failed (fetch threw) */
|
|
14
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
15
|
+
/** Server returned non-JSON response */
|
|
16
|
+
PARSE_ERROR: "PARSE_ERROR",
|
|
17
|
+
/** Server returned error without structured error body */
|
|
18
|
+
UNKNOWN_ERROR: "UNKNOWN_ERROR",
|
|
19
|
+
/** Input validation failed (empty required parameters) */
|
|
20
|
+
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
21
|
+
};
|
|
22
|
+
var noopLogger = {
|
|
23
|
+
debug: () => {
|
|
24
|
+
},
|
|
25
|
+
info: () => {
|
|
26
|
+
},
|
|
27
|
+
warn: () => {
|
|
28
|
+
},
|
|
29
|
+
error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
|
|
30
|
+
};
|
|
31
|
+
var consoleLogger = {
|
|
32
|
+
debug: (...args) => console.debug(SDK_LOG_PREFIX, ...args),
|
|
33
|
+
info: (...args) => console.info(SDK_LOG_PREFIX, ...args),
|
|
34
|
+
warn: (...args) => console.warn(SDK_LOG_PREFIX, ...args),
|
|
35
|
+
error: (...args) => console.error(SDK_LOG_PREFIX, ...args)
|
|
36
|
+
};
|
|
37
|
+
function createFFIDLegalClient(config) {
|
|
38
|
+
if (!config.apiKey) {
|
|
39
|
+
throw new Error("FFID Legal Client: apiKey \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
|
|
40
|
+
}
|
|
41
|
+
const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
|
|
42
|
+
const logger = config.logger ?? (config.debug ? consoleLogger : noopLogger);
|
|
43
|
+
async function fetchWithApiKey(endpoint, options = {}) {
|
|
44
|
+
const url = `${baseUrl}${API_PREFIX}${endpoint}`;
|
|
45
|
+
logger.debug("Fetching:", url);
|
|
46
|
+
let response;
|
|
47
|
+
try {
|
|
48
|
+
response = await fetch(url, {
|
|
49
|
+
...options,
|
|
50
|
+
headers: {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
"X-Service-Api-Key": config.apiKey,
|
|
53
|
+
...options.headers
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.error("Network error:", { url, error });
|
|
58
|
+
return {
|
|
59
|
+
error: {
|
|
60
|
+
code: FFID_LEGAL_ERROR_CODES.NETWORK_ERROR,
|
|
61
|
+
message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (response.status === NO_CONTENT_STATUS) {
|
|
66
|
+
logger.debug("Response: 204 No Content (unexpected)", { url });
|
|
67
|
+
return {
|
|
68
|
+
error: {
|
|
69
|
+
code: FFID_LEGAL_ERROR_CODES.UNKNOWN_ERROR,
|
|
70
|
+
message: "\u4E88\u671F\u3057\u306A\u3044\u30EC\u30B9\u30DD\u30F3\u30B9: \u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30B3\u30F3\u30C6\u30F3\u30C4\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
let data;
|
|
75
|
+
try {
|
|
76
|
+
data = await response.json();
|
|
77
|
+
} catch (parseError) {
|
|
78
|
+
logger.error("Parse error:", { url, status: response.status, parseError });
|
|
79
|
+
return {
|
|
80
|
+
error: {
|
|
81
|
+
code: FFID_LEGAL_ERROR_CODES.PARSE_ERROR,
|
|
82
|
+
message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
logger.debug("Response:", response.status, data);
|
|
87
|
+
if (!response.ok || !data.success) {
|
|
88
|
+
return {
|
|
89
|
+
error: data.error ?? {
|
|
90
|
+
code: FFID_LEGAL_ERROR_CODES.UNKNOWN_ERROR,
|
|
91
|
+
message: "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (data.data === void 0) {
|
|
96
|
+
return {
|
|
97
|
+
error: {
|
|
98
|
+
code: FFID_LEGAL_ERROR_CODES.UNKNOWN_ERROR,
|
|
99
|
+
message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return { data: data.data };
|
|
104
|
+
}
|
|
105
|
+
async function getDocuments() {
|
|
106
|
+
return fetchWithApiKey("/documents");
|
|
107
|
+
}
|
|
108
|
+
async function getDocument(documentId) {
|
|
109
|
+
if (!documentId) {
|
|
110
|
+
return {
|
|
111
|
+
error: {
|
|
112
|
+
code: FFID_LEGAL_ERROR_CODES.VALIDATION_ERROR,
|
|
113
|
+
message: "documentId is required"
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return fetchWithApiKey(`/documents/${encodeURIComponent(documentId)}`);
|
|
118
|
+
}
|
|
119
|
+
async function recordAgreement(request) {
|
|
120
|
+
if (!request.externalUserId || !request.documentId) {
|
|
121
|
+
return {
|
|
122
|
+
error: {
|
|
123
|
+
code: FFID_LEGAL_ERROR_CODES.VALIDATION_ERROR,
|
|
124
|
+
message: "externalUserId and documentId are required"
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return fetchWithApiKey("/agreements", {
|
|
129
|
+
method: "POST",
|
|
130
|
+
body: JSON.stringify(request)
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async function checkAgreement(externalUserId, documentId) {
|
|
134
|
+
if (!externalUserId || !documentId) {
|
|
135
|
+
return {
|
|
136
|
+
error: {
|
|
137
|
+
code: FFID_LEGAL_ERROR_CODES.VALIDATION_ERROR,
|
|
138
|
+
message: "externalUserId and documentId are required"
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const params = new URLSearchParams({
|
|
143
|
+
externalUserId,
|
|
144
|
+
documentId
|
|
145
|
+
});
|
|
146
|
+
return fetchWithApiKey(`/agreements/check?${params.toString()}`);
|
|
147
|
+
}
|
|
148
|
+
async function getPendingAgreements(externalUserId) {
|
|
149
|
+
if (!externalUserId) {
|
|
150
|
+
return {
|
|
151
|
+
error: {
|
|
152
|
+
code: FFID_LEGAL_ERROR_CODES.VALIDATION_ERROR,
|
|
153
|
+
message: "externalUserId is required"
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const params = new URLSearchParams({ externalUserId });
|
|
158
|
+
return fetchWithApiKey(`/agreements/pending?${params.toString()}`);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
/** Get all legal documents available to this service */
|
|
162
|
+
getDocuments,
|
|
163
|
+
/** Get a specific legal document by ID */
|
|
164
|
+
getDocument,
|
|
165
|
+
/** Record a user's agreement to a legal document */
|
|
166
|
+
recordAgreement,
|
|
167
|
+
/** Check if a user has agreed to a specific document */
|
|
168
|
+
checkAgreement,
|
|
169
|
+
/** Get all documents that a user has not yet agreed to */
|
|
170
|
+
getPendingAgreements,
|
|
171
|
+
/** Resolved logger instance */
|
|
172
|
+
logger,
|
|
173
|
+
/** API base URL */
|
|
174
|
+
baseUrl
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;
|
|
179
|
+
exports.FFID_LEGAL_ERROR_CODES = FFID_LEGAL_ERROR_CODES;
|
|
180
|
+
exports.createFFIDLegalClient = createFFIDLegalClient;
|