@kerne/react 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,208 +1,186 @@
1
- // src/index.tsx
2
- import { createContext, useContext, useEffect, useState, useMemo } from "react";
3
- import { Kerne } from "@kerne/server";
1
+ "use client";
2
+ import {
3
+ KerneClient,
4
+ KerneContext,
5
+ KerneProvider,
6
+ defaultLocalization,
7
+ useAccess,
8
+ useAuth,
9
+ useAuthConfig,
10
+ useCheckout,
11
+ useClient,
12
+ useEntitlements,
13
+ useInvitation,
14
+ usePlans,
15
+ usePortal,
16
+ useSubscription,
17
+ useUsage,
18
+ useUser,
19
+ useWaitlist
20
+ } from "./chunk-AIUIBAYB.js";
21
+
22
+ // src/components.tsx
23
+ import React from "react";
4
24
  import { jsx } from "react/jsx-runtime";
5
- var DEFAULT_STORAGE_KEY = "kerne_auth";
6
- var KerneClient = class {
7
- kerne;
8
- storage;
9
- storageKey;
10
- onAuthChange;
11
- currentUser = null;
12
- currentToken = null;
13
- constructor(config) {
14
- this.storage = config.storage ?? (typeof window !== "undefined" ? localStorage : null);
15
- this.storageKey = config.storageKey ?? DEFAULT_STORAGE_KEY;
16
- this.onAuthChange = config.onAuthChange;
17
- this.kerne = new Kerne({
18
- baseUrl: config.baseUrl,
19
- appId: config.appId,
20
- timeout: config.timeout
21
- });
22
- this.loadSession();
23
- }
24
- loadSession() {
25
- if (!this.storage) return;
26
- try {
27
- const data = this.storage.getItem(this.storageKey);
28
- if (data) {
29
- const { user, token, expires_at } = JSON.parse(data);
30
- if (new Date(expires_at) > /* @__PURE__ */ new Date()) {
31
- this.currentUser = user;
32
- this.currentToken = token;
33
- this.kerne = this.kerne.withToken(token);
34
- } else {
35
- this.storage.removeItem(this.storageKey);
36
- }
37
- }
38
- } catch {
39
- this.storage.removeItem(this.storageKey);
40
- }
41
- }
42
- saveSession(response) {
43
- this.currentUser = response.user;
44
- this.currentToken = response.token;
45
- this.kerne = this.kerne.withToken(response.token);
46
- if (this.storage) {
47
- this.storage.setItem(this.storageKey, JSON.stringify(response));
48
- }
49
- this.onAuthChange?.(response.user);
50
- }
51
- clearSession() {
52
- this.currentUser = null;
53
- this.currentToken = null;
54
- if (this.storage) {
55
- this.storage.removeItem(this.storageKey);
56
- }
57
- this.onAuthChange?.(null);
58
- }
59
- get user() {
60
- return this.currentUser;
61
- }
62
- get token() {
63
- return this.currentToken;
64
- }
65
- get isAuthenticated() {
66
- return this.currentToken !== null;
67
- }
68
- get client() {
69
- return this.kerne;
70
- }
71
- get projects() {
72
- return this.kerne.projects;
73
- }
74
- async register(params) {
75
- const [firstName, ...lastNameParts] = (params.name || "").split(" ");
76
- const lastName = lastNameParts.join(" ");
77
- const response = await this.kerne.auth.signup({
78
- email: params.email,
79
- password: params.password,
80
- first_name: firstName,
81
- last_name: lastName || void 0
82
- });
83
- this.saveSession(response);
84
- return response;
85
- }
86
- async login(params) {
87
- const response = await this.kerne.auth.login({
88
- email: params.email,
89
- password: params.password
90
- });
91
- this.saveSession(response);
92
- return response;
93
- }
94
- async refreshToken() {
95
- if (!this.currentToken) return null;
96
- const response = await this.kerne.auth.refreshToken({
97
- refresh_token: this.currentToken
25
+ function Authenticated({ children, fallback = null }) {
26
+ const { isAuthenticated } = useAuth();
27
+ return isAuthenticated ? children : fallback;
28
+ }
29
+ function Unauthenticated({ children, fallback = null }) {
30
+ const { isAuthenticated } = useAuth();
31
+ return !isAuthenticated ? children : fallback;
32
+ }
33
+ function AuthLoading({ children }) {
34
+ const client = useClient();
35
+ return client.isLoading ? children : null;
36
+ }
37
+ function HasSubscription({ children, fallback = null }) {
38
+ const client = useClient();
39
+ const [hasSubscription, setHasSubscription] = React.useState(null);
40
+ React.useEffect(() => {
41
+ client.getSubscription().then((sub) => {
42
+ setHasSubscription(sub !== null && ["ACTIVE", "TRIALING"].includes(sub.status));
43
+ }).catch(() => {
44
+ setHasSubscription(false);
98
45
  });
99
- this.saveSession(response);
100
- return response;
101
- }
102
- logout() {
103
- this.clearSession();
104
- }
105
- async refreshUser() {
106
- if (!this.currentToken) return null;
107
- try {
108
- const user = await this.kerne.users.me();
109
- this.currentUser = user;
110
- this.onAuthChange?.(user);
111
- return user;
112
- } catch {
113
- this.clearSession();
114
- return null;
115
- }
116
- }
117
- async checkEntitlement(featureKey, requested) {
118
- try {
119
- const check = await this.kerne.billing.checkEntitlement(featureKey, requested);
120
- return check.has_access;
121
- } catch {
122
- return false;
123
- }
124
- }
125
- async createCheckout(planId, options) {
126
- const { url } = await this.kerne.billing.createCheckout(planId, {
127
- success_url: options?.successUrl,
128
- cancel_url: options?.cancelUrl
46
+ }, [client]);
47
+ if (hasSubscription === null) return null;
48
+ return hasSubscription ? children : fallback;
49
+ }
50
+ function Allows({
51
+ children,
52
+ featureKey,
53
+ minimum,
54
+ fallback = null
55
+ }) {
56
+ const client = useClient();
57
+ const [allowed, setAllowed] = React.useState(null);
58
+ React.useEffect(() => {
59
+ client.allows(featureKey, minimum).then((result) => {
60
+ setAllowed(result);
61
+ }).catch(() => {
62
+ setAllowed(false);
129
63
  });
130
- return url;
131
- }
132
- async openCheckout(planId, options) {
133
- const url = await this.createCheckout(planId, options);
134
- if (typeof window !== "undefined") {
135
- window.location.href = url;
64
+ }, [client, featureKey, minimum]);
65
+ if (allowed === null) return null;
66
+ return allowed ? children : fallback;
67
+ }
68
+ function Protected({
69
+ children,
70
+ auth = true,
71
+ featureKey,
72
+ authFallback = null,
73
+ billingFallback = null
74
+ }) {
75
+ const { isAuthenticated } = useAuth();
76
+ if (auth && !isAuthenticated) {
77
+ return authFallback;
78
+ }
79
+ if (featureKey) {
80
+ return /* @__PURE__ */ jsx(Allows, { featureKey, fallback: billingFallback, children });
81
+ }
82
+ return children;
83
+ }
84
+
85
+ // src/error-boundary.tsx
86
+ import React2, { Component } from "react";
87
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
88
+ var KerneErrorBoundary = class extends Component {
89
+ constructor(props) {
90
+ super(props);
91
+ this.state = { error: null, hasError: false };
92
+ }
93
+ static getDerivedStateFromError(error) {
94
+ return { error, hasError: true };
95
+ }
96
+ componentDidCatch(error, errorInfo) {
97
+ const kerneError = error;
98
+ this.props.onError?.(kerneError, errorInfo);
99
+ if (process.env.NODE_ENV === "development") {
100
+ console.error("[KerneSDK] Error caught by boundary:", kerneError);
101
+ console.error("[KerneSDK] Component stack:", errorInfo.componentStack);
136
102
  }
137
103
  }
138
- async createPortal(returnUrl) {
139
- const { url } = await this.kerne.billing.createPortal({ return_url: returnUrl });
140
- return url;
141
- }
142
- async openPortal(returnUrl) {
143
- const url = await this.createPortal(returnUrl);
144
- if (typeof window !== "undefined") {
145
- window.location.href = url;
104
+ reset = () => {
105
+ this.props.onReset?.();
106
+ this.setState({ error: null, hasError: false });
107
+ };
108
+ render() {
109
+ if (this.state.hasError && this.state.error) {
110
+ const { fallback } = this.props;
111
+ const { error } = this.state;
112
+ if (fallback) {
113
+ if (typeof fallback === "function") {
114
+ return fallback(error, this.reset);
115
+ }
116
+ return fallback;
117
+ }
118
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "20px", textAlign: "center" }, children: [
119
+ /* @__PURE__ */ jsx2("h2", { style: { color: "#dc2626", marginBottom: "10px" }, children: "Something went wrong" }),
120
+ /* @__PURE__ */ jsx2("p", { style: { color: "#6b7280", marginBottom: "20px" }, children: error.message || "An unexpected error occurred" }),
121
+ error.code && /* @__PURE__ */ jsxs("p", { style: { color: "#9ca3af", fontSize: "12px", marginBottom: "20px" }, children: [
122
+ "Error code: ",
123
+ error.code
124
+ ] }),
125
+ /* @__PURE__ */ jsx2(
126
+ "button",
127
+ {
128
+ onClick: this.reset,
129
+ style: {
130
+ padding: "10px 20px",
131
+ backgroundColor: "#3b82f6",
132
+ color: "white",
133
+ border: "none",
134
+ borderRadius: "6px",
135
+ cursor: "pointer"
136
+ },
137
+ children: "Try again"
138
+ }
139
+ )
140
+ ] });
146
141
  }
142
+ return this.props.children;
147
143
  }
148
144
  };
149
- function createKerneClient(config) {
150
- return new KerneClient(config);
151
- }
152
- var KerneContext = createContext(null);
153
- function KerneProvider({ children, ...config }) {
154
- const [user, setUser] = useState(null);
155
- const client = useMemo(() => {
156
- return new KerneClient({
157
- ...config,
158
- onAuthChange: (u) => {
159
- setUser(u);
160
- config.onAuthChange?.(u);
161
- }
162
- });
163
- }, [config.appId, config.baseUrl]);
164
- useEffect(() => {
165
- setUser(client.user);
166
- }, [client]);
167
- return /* @__PURE__ */ jsx(KerneContext.Provider, { value: client, children });
168
- }
169
- function useKerne() {
170
- const context = useContext(KerneContext);
171
- if (!context) {
172
- throw new Error("useKerne must be used within a KerneProvider");
173
- }
174
- return context;
175
- }
176
- function useAuth() {
177
- const client = useKerne();
178
- const [user, setUser] = useState(client.user);
179
- useEffect(() => {
180
- setUser(client.user);
181
- }, [client.user]);
182
- return {
183
- user,
184
- isAuthenticated: client.isAuthenticated,
185
- login: client.login.bind(client),
186
- register: client.register.bind(client),
187
- logout: client.logout.bind(client),
188
- refreshUser: client.refreshUser.bind(client)
189
- };
190
- }
191
- function useBilling() {
192
- const client = useKerne();
145
+ function useKerneError() {
146
+ const [error, setError] = React2.useState(null);
147
+ const handleError = React2.useCallback((err) => {
148
+ setError(err);
149
+ }, []);
150
+ const clearError = React2.useCallback(() => {
151
+ setError(null);
152
+ }, []);
193
153
  return {
194
- checkEntitlement: client.checkEntitlement.bind(client),
195
- createCheckout: client.createCheckout.bind(client),
196
- openCheckout: client.openCheckout.bind(client),
197
- createPortal: client.createPortal.bind(client),
198
- openPortal: client.openPortal.bind(client)
154
+ error,
155
+ hasError: error !== null,
156
+ handleError,
157
+ clearError
199
158
  };
200
159
  }
201
160
  export {
161
+ Allows,
162
+ AuthLoading,
163
+ Authenticated,
164
+ HasSubscription,
202
165
  KerneClient,
166
+ KerneContext,
167
+ KerneErrorBoundary,
203
168
  KerneProvider,
204
- createKerneClient,
169
+ Protected,
170
+ Unauthenticated,
171
+ defaultLocalization,
172
+ useAccess,
205
173
  useAuth,
206
- useBilling,
207
- useKerne
174
+ useAuthConfig,
175
+ useCheckout,
176
+ useClient,
177
+ useEntitlements,
178
+ useInvitation,
179
+ useKerneError,
180
+ usePlans,
181
+ usePortal,
182
+ useSubscription,
183
+ useUsage,
184
+ useUser,
185
+ useWaitlist
208
186
  };