@howone/sdk 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
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,10 +30,224 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // src/auth/index.ts
34
+ var auth_exports = {};
35
+ __export(auth_exports, {
36
+ AUTH_TOKEN_KEY: () => AUTH_TOKEN_KEY,
37
+ getToken: () => getToken,
38
+ isTokenValid: () => isTokenValid,
39
+ onAuthStateChanged: () => onAuthStateChanged,
40
+ parseUserFromToken: () => parseUserFromToken,
41
+ setToken: () => setToken,
42
+ useAuth: () => useAuth
43
+ });
44
+ function setCookie(name, value, days = 30) {
45
+ try {
46
+ if (typeof document === "undefined") return;
47
+ if (!value) {
48
+ document.cookie = `${name}=; Max-Age=0; path=/; SameSite=Lax`;
49
+ return;
50
+ }
51
+ const expires = new Date(Date.now() + days * 24 * 60 * 60 * 1e3).toUTCString();
52
+ document.cookie = `${name}=${encodeURIComponent(value)}; Expires=${expires}; Path=/; SameSite=Lax`;
53
+ } catch (e) {
54
+ void e;
55
+ }
56
+ }
57
+ function getCookie(name) {
58
+ try {
59
+ if (typeof document === "undefined") return null;
60
+ const match = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([.$?*|{}()\[\]\\/+^])/g, "\\$1") + "=([^;]*)"));
61
+ return match ? decodeURIComponent(match[1]) : null;
62
+ } catch (e) {
63
+ return null;
64
+ }
65
+ }
66
+ function setToken(token) {
67
+ try {
68
+ setCookie(AUTH_TOKEN_KEY, token, 30);
69
+ } catch (e) {
70
+ void e;
71
+ }
72
+ if (!token) {
73
+ try {
74
+ notifyAuthStateChanged();
75
+ } catch {
76
+ }
77
+ return;
78
+ }
79
+ try {
80
+ notifyAuthStateChanged();
81
+ } catch {
82
+ }
83
+ }
84
+ function getToken() {
85
+ try {
86
+ const cookie = getCookie(AUTH_TOKEN_KEY);
87
+ if (cookie) return cookie;
88
+ } catch (e) {
89
+ void e;
90
+ }
91
+ return null;
92
+ }
93
+ function decodeJwtPayload(token) {
94
+ try {
95
+ const payload = token.split(".")[1];
96
+ if (!payload) return null;
97
+ let base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
98
+ const pad = base64.length % 4;
99
+ if (pad === 2) base64 += "==";
100
+ else if (pad === 3) base64 += "=";
101
+ else if (pad !== 0) return null;
102
+ const json = atob(base64);
103
+ return JSON.parse(json);
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+ function parseUserFromToken(token) {
109
+ if (!token) return null;
110
+ const payload = decodeJwtPayload(token);
111
+ if (!payload) return null;
112
+ return {
113
+ id: payload.userId || payload.sub || "",
114
+ email: payload.email || "",
115
+ name: payload.name || "",
116
+ avatar: payload.avatar || payload.picture || ""
117
+ };
118
+ }
119
+ function isTokenValid(token) {
120
+ if (!token) return false;
121
+ const payload = decodeJwtPayload(token);
122
+ if (!payload) return false;
123
+ const now = Math.floor(Date.now() / 1e3);
124
+ const expCandidate = payload.exp ?? payload.expires_at;
125
+ const exp = Number(expCandidate);
126
+ if (!exp || !Number.isFinite(exp)) return true;
127
+ return exp > now;
128
+ }
129
+ function useAuth() {
130
+ const [token, setTokenState] = (0, import_react.useState)(() => getToken());
131
+ const [user, setUser] = (0, import_react.useState)(() => parseUserFromToken(getToken()));
132
+ (0, import_react.useEffect)(() => {
133
+ const onStorage = () => {
134
+ const t = getToken();
135
+ setTokenState(t);
136
+ setUser(parseUserFromToken(t));
137
+ };
138
+ window.addEventListener("storage", onStorage);
139
+ const unsubscribe = onAuthStateChanged(() => {
140
+ setTokenState(getToken());
141
+ setUser(parseUserFromToken(getToken()));
142
+ });
143
+ return () => {
144
+ window.removeEventListener("storage", onStorage);
145
+ unsubscribe();
146
+ };
147
+ }, []);
148
+ const logout = () => {
149
+ setToken(null);
150
+ setTokenState(null);
151
+ setUser(null);
152
+ notifyAuthStateChanged();
153
+ };
154
+ return {
155
+ token,
156
+ user,
157
+ isAuthenticated: !!token && isTokenValid(token),
158
+ logout
159
+ };
160
+ }
161
+ function onAuthStateChanged(cb) {
162
+ try {
163
+ const current = { user: parseUserFromToken(getToken()), isLoading: false };
164
+ cb(current);
165
+ } catch {
166
+ }
167
+ authSubscribers.add(cb);
168
+ return () => {
169
+ authSubscribers.delete(cb);
170
+ };
171
+ }
172
+ function notifyAuthStateChanged() {
173
+ const state = { user: parseUserFromToken(getToken()), isLoading: false };
174
+ for (const cb of Array.from(authSubscribers)) {
175
+ try {
176
+ cb(state);
177
+ } catch {
178
+ }
179
+ }
180
+ }
181
+ var import_react, AUTH_TOKEN_KEY, authSubscribers;
182
+ var init_auth = __esm({
183
+ "src/auth/index.ts"() {
184
+ "use strict";
185
+ import_react = require("react");
186
+ AUTH_TOKEN_KEY = "auth_token";
187
+ authSubscribers = /* @__PURE__ */ new Set();
188
+ }
189
+ });
190
+
191
+ // src/config.ts
192
+ var config_exports = {};
193
+ __export(config_exports, {
194
+ AUTH_ROOT: () => AUTH_ROOT,
195
+ default: () => config_default,
196
+ getAuthRoot: () => getAuthRoot,
197
+ getDefaultProjectId: () => getDefaultProjectId,
198
+ setAuthRoot: () => setAuthRoot,
199
+ setDefaultProjectId: () => setDefaultProjectId
200
+ });
201
+ function setAuthRoot(url) {
202
+ AUTH_ROOT_VALUE = url.replace(/\/+$/g, "");
203
+ }
204
+ function getAuthRoot() {
205
+ return AUTH_ROOT_VALUE;
206
+ }
207
+ function setDefaultProjectId(id) {
208
+ DEFAULT_PROJECT_ID = id;
209
+ }
210
+ function getDefaultProjectId() {
211
+ try {
212
+ if (DEFAULT_PROJECT_ID) return DEFAULT_PROJECT_ID;
213
+ const g = globalThis.__HOWONE_PROJECT_ID__;
214
+ if (typeof g === "string" && g.length > 0) return String(g);
215
+ return null;
216
+ } catch {
217
+ return DEFAULT_PROJECT_ID;
218
+ }
219
+ }
220
+ var AUTH_ROOT_VALUE, DEFAULT_PROJECT_ID, AUTH_ROOT, config_default;
221
+ var init_config = __esm({
222
+ "src/config.ts"() {
223
+ "use strict";
224
+ AUTH_ROOT_VALUE = "http://localhost:3000";
225
+ DEFAULT_PROJECT_ID = null;
226
+ AUTH_ROOT = getAuthRoot();
227
+ try {
228
+ const g = globalThis.__HOWONE_AUTH_ROOT__;
229
+ if (typeof g === "string" && g.length > 0) {
230
+ setAuthRoot(g);
231
+ }
232
+ } catch {
233
+ }
234
+ config_default = {
235
+ getAuthRoot,
236
+ setAuthRoot,
237
+ AUTH_ROOT: () => AUTH_ROOT_VALUE
238
+ };
239
+ }
240
+ });
241
+
30
242
  // src/index.ts
31
243
  var index_exports = {};
32
244
  __export(index_exports, {
245
+ AUTH_ROOT: () => AUTH_ROOT,
246
+ AUTH_TOKEN_KEY: () => AUTH_TOKEN_KEY,
33
247
  AuthGuard: () => AuthGuard,
248
+ AuthProvider: () => AuthProvider,
249
+ AuthRedirector: () => AuthRedirector,
250
+ AuthRedirectorDefault: () => AuthRedirector_default,
34
251
  DefaultErrorFallback: () => DefaultErrorFallback,
35
252
  ErrorBoundary: () => ErrorBoundary,
36
253
  FloatingButton: () => FloatingButton,
@@ -44,13 +261,25 @@ __export(index_exports, {
44
261
  createAIWorkflowClientAxios: () => createAIWorkflowClientAxios,
45
262
  createArtifactsClient: () => createArtifactsClient,
46
263
  createClient: () => createClient,
264
+ getAuthRoot: () => getAuthRoot,
47
265
  getCodeStatus: () => getCodeStatus,
266
+ getDefaultProjectId: () => getDefaultProjectId,
267
+ getToken: () => getToken,
268
+ howone: () => client_default,
48
269
  injectEarlyErrorHandler: () => injectEarlyErrorHandler,
270
+ isTokenValid: () => isTokenValid,
49
271
  loginWithEmailCode: () => loginWithEmailCode,
272
+ onAuthStateChanged: () => onAuthStateChanged,
273
+ parseUserFromToken: () => parseUserFromToken,
50
274
  request: () => request,
51
275
  sendEmailVerificationCode: () => sendEmailVerificationCode,
276
+ setAuthRoot: () => setAuthRoot,
277
+ setDefaultProjectId: () => setDefaultProjectId,
278
+ setToken: () => setToken,
52
279
  unifiedAuth: () => unifiedAuth,
53
280
  unifiedOAuth: () => unifiedOAuth,
281
+ useAuth: () => useAuth,
282
+ useAuthContext: () => useAuthContext,
54
283
  useDebounce: () => useDebounce,
55
284
  useIsMobile: () => useIsMobile,
56
285
  useLocalStorage: () => useLocalStorage,
@@ -342,9 +571,21 @@ var UnifiedAuthService = class {
342
571
  checkOAuthCallback() {
343
572
  const urlParams = new URLSearchParams(window.location.search);
344
573
  const token = urlParams.get("token");
574
+ const accessTokenQuery = urlParams.get("access_token");
345
575
  const error = urlParams.get("error");
346
576
  const userParam = urlParams.get("user");
347
- if (token) {
577
+ let hashToken = null;
578
+ try {
579
+ if (window.location.hash && window.location.hash.length > 1) {
580
+ const hash = window.location.hash.slice(1);
581
+ const hashParams = new URLSearchParams(hash);
582
+ hashToken = hashParams.get("access_token") || hashParams.get("token") || null;
583
+ }
584
+ } catch {
585
+ hashToken = null;
586
+ }
587
+ const finalToken = accessTokenQuery || token || hashToken;
588
+ if (finalToken) {
348
589
  let user = null;
349
590
  if (userParam) {
350
591
  try {
@@ -352,9 +593,20 @@ var UnifiedAuthService = class {
352
593
  } catch (e) {
353
594
  }
354
595
  }
355
- this.saveAuthData(token, user);
356
- window.history.replaceState({}, document.title, window.location.pathname);
357
- return { success: true, token, user };
596
+ this.saveAuthData(finalToken);
597
+ try {
598
+ const u = new URL(window.location.href);
599
+ u.searchParams.delete("token");
600
+ u.searchParams.delete("access_token");
601
+ u.hash = "";
602
+ window.history.replaceState({}, document.title, u.toString());
603
+ } catch (e) {
604
+ try {
605
+ window.history.replaceState({}, document.title, window.location.pathname);
606
+ } catch {
607
+ }
608
+ }
609
+ return { success: true, token: finalToken, user };
358
610
  }
359
611
  if (error) {
360
612
  window.history.replaceState({}, document.title, window.location.pathname);
@@ -395,18 +647,15 @@ var UnifiedAuthService = class {
395
647
  */
396
648
  getSavedAuthData() {
397
649
  try {
398
- const token = localStorage.getItem("auth_token");
399
- if (!token) return null;
400
- let user = null;
401
- const userJson = localStorage.getItem("auth_user");
402
- if (userJson) {
403
- try {
404
- user = JSON.parse(userJson);
405
- } catch (e) {
406
- console.error("Failed to parse saved user data:", e);
407
- }
650
+ let token = null;
651
+ try {
652
+ const { getToken: getToken2 } = (init_auth(), __toCommonJS(auth_exports));
653
+ if (getToken2) token = getToken2();
654
+ } catch {
655
+ token = null;
408
656
  }
409
- return { token, user };
657
+ if (!token) return null;
658
+ return { token };
410
659
  } catch (e) {
411
660
  console.error("Failed to get auth data from localStorage:", e);
412
661
  return null;
@@ -415,10 +664,13 @@ var UnifiedAuthService = class {
415
664
  /**
416
665
  * 保存认证数据到本地存储
417
666
  */
418
- saveAuthData(token, user) {
667
+ saveAuthData(token) {
419
668
  try {
420
- localStorage.setItem("auth_token", token);
421
- localStorage.setItem("auth_user", JSON.stringify(user || {}));
669
+ try {
670
+ const { setToken: setToken2 } = (init_auth(), __toCommonJS(auth_exports));
671
+ if (setToken2) setToken2(token);
672
+ } catch {
673
+ }
422
674
  } catch (e) {
423
675
  console.error("Failed to save auth data to localStorage:", e);
424
676
  }
@@ -691,6 +943,9 @@ function createArtifactsClient(req) {
691
943
  }
692
944
 
693
945
  // src/services/index.ts
946
+ init_auth();
947
+ init_config();
948
+ init_config();
694
949
  var request = new request_default({
695
950
  baseURL: "https://create-x-backend.fly.dev/api",
696
951
  timeout: 6e4,
@@ -734,6 +989,12 @@ function createClient(opts) {
734
989
  const biz = opts?.requestInstance || request;
735
990
  const ai = opts?.aiRequestInstance || aiRequest;
736
991
  let token = null;
992
+ try {
993
+ if (opts?.projectId) {
994
+ setDefaultProjectId(String(opts.projectId));
995
+ }
996
+ } catch {
997
+ }
737
998
  function applyToken(t) {
738
999
  try {
739
1000
  try {
@@ -813,6 +1074,8 @@ function createClient(opts) {
813
1074
  } catch (_e) {
814
1075
  }
815
1076
  return {
1077
+ // expose projectId so consumers can read it from the client instance
1078
+ projectId: opts?.projectId ?? null,
816
1079
  request: biz,
817
1080
  aiRequest: ai,
818
1081
  workflowRequest: ai,
@@ -828,11 +1091,19 @@ function createClient(opts) {
828
1091
  isAuthenticated: () => Boolean(token),
829
1092
  // minimal login/logout stubs - consumers can override behavior
830
1093
  login: (redirect) => {
831
- if (opts?.authRequired) {
832
- if (typeof window !== "undefined") {
833
- const loc = redirect || window.location.href;
834
- window.location.href = `/login?redirect=${encodeURIComponent(loc)}`;
835
- }
1094
+ if (typeof window === "undefined") return;
1095
+ const loc = redirect || window.location.href;
1096
+ try {
1097
+ const root = getAuthRoot() || "http://localhost:3000";
1098
+ const authUrl = new URL("/auth", String(root));
1099
+ authUrl.searchParams.set("redirect_uri", String(loc));
1100
+ if (opts?.projectId) authUrl.searchParams.set("project_id", String(opts.projectId));
1101
+ window.location.href = authUrl.toString();
1102
+ } catch {
1103
+ const encoded = encodeURIComponent(String(loc));
1104
+ const pid = opts?.projectId ? `&project_id=${encodeURIComponent(String(opts.projectId))}` : "";
1105
+ const root = "http://localhost:3000";
1106
+ window.location.href = `${root}/auth?redirect_uri=${encoded}${pid}`;
836
1107
  }
837
1108
  },
838
1109
  logout: () => {
@@ -844,8 +1115,8 @@ function createClient(opts) {
844
1115
  }
845
1116
 
846
1117
  // src/components/auth/LoginForm.tsx
847
- var import_react = require("react");
848
- var import_react2 = require("@iconify/react");
1118
+ var import_react2 = require("react");
1119
+ var import_react3 = require("@iconify/react");
849
1120
  var import_lucide_react = require("lucide-react");
850
1121
  var import_jsx_runtime2 = require("react/jsx-runtime");
851
1122
  var LoginForm = ({
@@ -853,12 +1124,12 @@ var LoginForm = ({
853
1124
  appName = "AI Application Platform",
854
1125
  className = ""
855
1126
  }) => {
856
- const [email, setEmail] = (0, import_react.useState)("");
857
- const [code, setCode] = (0, import_react.useState)("");
858
- const [validationErrors, setValidationErrors] = (0, import_react.useState)({});
859
- const [isAnyLoading, setIsAnyLoading] = (0, import_react.useState)(false);
860
- const [codeSent, setCodeSent] = (0, import_react.useState)(false);
861
- const [loginError, setLoginError] = (0, import_react.useState)(null);
1127
+ const [email, setEmail] = (0, import_react2.useState)("");
1128
+ const [code, setCode] = (0, import_react2.useState)("");
1129
+ const [validationErrors, setValidationErrors] = (0, import_react2.useState)({});
1130
+ const [isAnyLoading, setIsAnyLoading] = (0, import_react2.useState)(false);
1131
+ const [codeSent, setCodeSent] = (0, import_react2.useState)(false);
1132
+ const [loginError, setLoginError] = (0, import_react2.useState)(null);
862
1133
  const googleLogin = async () => {
863
1134
  console.log("Google login clicked");
864
1135
  };
@@ -877,7 +1148,7 @@ var LoginForm = ({
877
1148
  setLoginError(null);
878
1149
  setValidationErrors({});
879
1150
  };
880
- (0, import_react.useEffect)(() => {
1151
+ (0, import_react2.useEffect)(() => {
881
1152
  if (loginError) {
882
1153
  try {
883
1154
  const errorObj = JSON.parse(loginError);
@@ -999,7 +1270,7 @@ var LoginForm = ({
999
1270
  validationErrors.code && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-red-600 text-sm", children: validationErrors.code })
1000
1271
  ] }),
1001
1272
  validationErrors.form && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-red-600 text-sm p-3 bg-red-50 rounded-md border border-red-200", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center", children: [
1002
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Icon, { icon: "material-symbols:error", className: "text-red-600 mr-2" }),
1273
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Icon, { icon: "material-symbols:error", className: "text-red-600 mr-2" }),
1003
1274
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: validationErrors.form })
1004
1275
  ] }) }),
1005
1276
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
@@ -1033,7 +1304,7 @@ var LoginForm = ({
1033
1304
  },
1034
1305
  disabled: isAnyLoading,
1035
1306
  children: [
1036
- isAnyLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Icon, { icon: "flat-color-icons:google", className: "w-6 h-6 mr-2" }),
1307
+ isAnyLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Icon, { icon: "flat-color-icons:google", className: "w-6 h-6 mr-2" }),
1037
1308
  isAnyLoading ? "Connecting..." : "Log in with Google"
1038
1309
  ]
1039
1310
  }
@@ -1050,7 +1321,7 @@ var LoginForm = ({
1050
1321
  },
1051
1322
  disabled: isAnyLoading,
1052
1323
  children: [
1053
- isAnyLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Icon, { icon: "mdi:github", className: "w-6 h-6 mr-2" }),
1324
+ isAnyLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Icon, { icon: "mdi:github", className: "w-6 h-6 mr-2" }),
1054
1325
  isAnyLoading ? "Connecting..." : "Log in with GitHub"
1055
1326
  ]
1056
1327
  }
@@ -1061,6 +1332,8 @@ var LoginForm = ({
1061
1332
 
1062
1333
  // src/components/auth/AuthGuard.tsx
1063
1334
  var import_react_router_dom = require("react-router-dom");
1335
+ init_auth();
1336
+ init_config();
1064
1337
  var import_jsx_runtime3 = require("react/jsx-runtime");
1065
1338
  var AuthGuard = ({
1066
1339
  children,
@@ -1070,8 +1343,8 @@ var AuthGuard = ({
1070
1343
  roles = [],
1071
1344
  permissions = []
1072
1345
  }) => {
1073
- const isAuthenticated = false;
1074
- const user = null;
1346
+ const { user: parsedUser, isAuthenticated } = useAuth();
1347
+ const user = parsedUser;
1075
1348
  const isLoading = false;
1076
1349
  const location = (0, import_react_router_dom.useLocation)();
1077
1350
  if (isLoading) {
@@ -1081,6 +1354,47 @@ var AuthGuard = ({
1081
1354
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "min-h-screen flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600" }) });
1082
1355
  }
1083
1356
  if (requireAuth && !isAuthenticated) {
1357
+ try {
1358
+ const urlParams = new URLSearchParams(window.location.search);
1359
+ const tokenInUrl = urlParams.get("token") || urlParams.get("access_token");
1360
+ let tokenInHash = null;
1361
+ try {
1362
+ if (window.location.hash && window.location.hash.length > 1) {
1363
+ const hashParams = new URLSearchParams(window.location.hash.slice(1));
1364
+ tokenInHash = hashParams.get("access_token") || hashParams.get("token");
1365
+ }
1366
+ } catch {
1367
+ tokenInHash = null;
1368
+ }
1369
+ const localToken = getToken();
1370
+ if (tokenInUrl || tokenInHash) {
1371
+ try {
1372
+ const res = unifiedAuth.checkOAuthCallback();
1373
+ if (res && res.success) {
1374
+ return null;
1375
+ }
1376
+ } catch {
1377
+ }
1378
+ }
1379
+ if (localToken) {
1380
+ return null;
1381
+ }
1382
+ } catch (e) {
1383
+ void e;
1384
+ }
1385
+ if (redirectTo === "/login") {
1386
+ const root = getAuthRoot() || "http://localhost:3000";
1387
+ try {
1388
+ const authUrl = new URL("/auth", String(root));
1389
+ authUrl.searchParams.set("redirect_uri", window.location.href);
1390
+ const pid = getDefaultProjectId();
1391
+ if (pid) authUrl.searchParams.set("project_id", pid);
1392
+ window.location.replace(authUrl.toString());
1393
+ } catch {
1394
+ window.location.replace(root);
1395
+ }
1396
+ return null;
1397
+ }
1084
1398
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_router_dom.Navigate, { to: redirectTo, state: { from: location }, replace: true });
1085
1399
  }
1086
1400
  if (roles.length > 0 && user !== null) {
@@ -1116,8 +1430,207 @@ var AuthGuard = ({
1116
1430
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
1117
1431
  };
1118
1432
 
1119
- // src/components/ui/Loading.tsx
1433
+ // src/components/auth/AuthRedirector.tsx
1434
+ var import_react4 = require("react");
1435
+ init_auth();
1436
+ init_config();
1120
1437
  var import_jsx_runtime4 = require("react/jsx-runtime");
1438
+ var AuthRedirector = ({ fallback }) => {
1439
+ (0, import_react4.useEffect)(() => {
1440
+ try {
1441
+ const cb = unifiedAuth.checkOAuthCallback();
1442
+ if (cb && cb.success) return;
1443
+ const unsubscribe = onAuthStateChanged((state) => {
1444
+ if (!state.user) {
1445
+ try {
1446
+ const root = getAuthRoot() || "http://localhost:3000";
1447
+ const authUrl = new URL("/auth", String(root));
1448
+ authUrl.searchParams.set("redirect_uri", window.location.href);
1449
+ const pid = getDefaultProjectId && getDefaultProjectId();
1450
+ if (pid) authUrl.searchParams.set("project_id", pid);
1451
+ window.location.replace(authUrl.toString());
1452
+ } catch {
1453
+ }
1454
+ }
1455
+ });
1456
+ return () => {
1457
+ try {
1458
+ unsubscribe();
1459
+ } catch {
1460
+ }
1461
+ };
1462
+ } catch {
1463
+ }
1464
+ }, []);
1465
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-h-screen flex items-center justify-center bg-white", children: fallback ?? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "text-lg font-semibold", children: "Redirecting to authentication..." }) }) });
1466
+ };
1467
+ var AuthRedirector_default = AuthRedirector;
1468
+
1469
+ // src/components/auth/AuthProvider.tsx
1470
+ var import_react5 = require("react");
1471
+ init_auth();
1472
+ init_config();
1473
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1474
+ var AuthContext = (0, import_react5.createContext)(null);
1475
+ var AuthProvider = ({ children, autoRedirect = true, showFloatingButton = true, projectId }) => {
1476
+ const [user, setUser] = (0, import_react5.useState)(() => parseUserFromToken(getToken()));
1477
+ const [token, setTokenState] = (0, import_react5.useState)(() => getToken());
1478
+ const [isLoading, setIsLoading] = (0, import_react5.useState)(false);
1479
+ (0, import_react5.useEffect)(() => {
1480
+ try {
1481
+ if (projectId) setDefaultProjectId(String(projectId));
1482
+ } catch {
1483
+ }
1484
+ setIsLoading(true);
1485
+ try {
1486
+ const cb = unifiedAuth.checkOAuthCallback();
1487
+ if (cb && cb.success) {
1488
+ setTokenState(cb.token ?? getToken());
1489
+ setUser(cb.user ?? parseUserFromToken(cb.token ?? getToken()));
1490
+ setIsLoading(false);
1491
+ return;
1492
+ }
1493
+ } catch {
1494
+ }
1495
+ const unsubscribe = onAuthStateChanged((state) => {
1496
+ try {
1497
+ setTokenState(getToken());
1498
+ setUser(state.user ?? parseUserFromToken(getToken()));
1499
+ } catch {
1500
+ }
1501
+ setIsLoading(false);
1502
+ if (autoRedirect && !state.user) {
1503
+ try {
1504
+ const root = getAuthRoot() || "http://localhost:3000";
1505
+ const authUrl = new URL("/auth", String(root));
1506
+ authUrl.searchParams.set("redirect_uri", window.location.href);
1507
+ const pid = getDefaultProjectId();
1508
+ if (pid) authUrl.searchParams.set("project_id", pid);
1509
+ window.location.replace(authUrl.toString());
1510
+ } catch {
1511
+ }
1512
+ }
1513
+ });
1514
+ return () => {
1515
+ try {
1516
+ unsubscribe();
1517
+ } catch {
1518
+ }
1519
+ };
1520
+ }, [autoRedirect]);
1521
+ const logout = () => {
1522
+ try {
1523
+ setToken(null);
1524
+ } catch {
1525
+ }
1526
+ setTokenState(null);
1527
+ setUser(null);
1528
+ };
1529
+ const value = {
1530
+ user,
1531
+ token,
1532
+ isAuthenticated: !!token,
1533
+ isLoading,
1534
+ logout
1535
+ };
1536
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(AuthContext.Provider, { value, children: [
1537
+ children,
1538
+ showFloatingButton && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") })
1539
+ ] });
1540
+ };
1541
+ function useAuthContext() {
1542
+ const ctx = (0, import_react5.useContext)(AuthContext);
1543
+ if (!ctx) {
1544
+ const t = getToken();
1545
+ return {
1546
+ user: parseUserFromToken(t),
1547
+ token: t,
1548
+ isAuthenticated: !!t,
1549
+ isLoading: false,
1550
+ logout: () => {
1551
+ try {
1552
+ setToken(null);
1553
+ } catch {
1554
+ }
1555
+ }
1556
+ };
1557
+ }
1558
+ return ctx;
1559
+ }
1560
+
1561
+ // src/components/index.ts
1562
+ init_auth();
1563
+
1564
+ // src/howone/client.ts
1565
+ init_auth();
1566
+ init_config();
1567
+ var HowoneAuthClient = class {
1568
+ constructor() {
1569
+ this.listeners = /* @__PURE__ */ new Set();
1570
+ this.loading = false;
1571
+ }
1572
+ emit() {
1573
+ const state = {
1574
+ user: parseUserFromToken(getToken()),
1575
+ isLoading: this.loading
1576
+ };
1577
+ for (const l of this.listeners) {
1578
+ try {
1579
+ l(state);
1580
+ } catch (e) {
1581
+ void e;
1582
+ }
1583
+ }
1584
+ }
1585
+ onAuthStateChanged(listener) {
1586
+ this.listeners.add(listener);
1587
+ try {
1588
+ listener({ user: parseUserFromToken(getToken()), isLoading: this.loading });
1589
+ } catch (e) {
1590
+ void e;
1591
+ }
1592
+ return () => {
1593
+ this.listeners.delete(listener);
1594
+ };
1595
+ }
1596
+ // Simple redirect-based login trigger (consumer can override)
1597
+ login() {
1598
+ const root = getAuthRoot() || "http://localhost:3000";
1599
+ try {
1600
+ const loc = window.location.href;
1601
+ const authUrl = new URL("/auth", String(root));
1602
+ authUrl.searchParams.set("redirect_uri", String(loc));
1603
+ try {
1604
+ const cfg = (init_config(), __toCommonJS(config_exports));
1605
+ const pid = cfg.getDefaultProjectId && cfg.getDefaultProjectId();
1606
+ if (pid) authUrl.searchParams.set("project_id", String(pid));
1607
+ } catch {
1608
+ }
1609
+ window.location.replace(authUrl.toString());
1610
+ } catch {
1611
+ window.location.replace(String(root));
1612
+ }
1613
+ }
1614
+ logout() {
1615
+ setToken(null);
1616
+ this.emit();
1617
+ }
1618
+ getUser() {
1619
+ return parseUserFromToken(getToken());
1620
+ }
1621
+ // helper to programmatically set token (e.g., after callback handling)
1622
+ setToken(token) {
1623
+ setToken(token);
1624
+ this.emit();
1625
+ }
1626
+ };
1627
+ var howone = {
1628
+ auth: new HowoneAuthClient()
1629
+ };
1630
+ var client_default = howone;
1631
+
1632
+ // src/components/ui/Loading.tsx
1633
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1121
1634
  var Loading = ({
1122
1635
  size = "md",
1123
1636
  text = "Loading...",
@@ -1130,14 +1643,14 @@ var Loading = ({
1130
1643
  lg: "h-12 w-12"
1131
1644
  };
1132
1645
  const containerClasses = fullScreen ? "fixed inset-0 flex items-center justify-center bg-white/80 backdrop-blur-sm z-50" : "flex items-center justify-center p-4";
1133
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "text-center", children: [
1134
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1646
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "text-center", children: [
1647
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1135
1648
  "div",
1136
1649
  {
1137
1650
  className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
1138
1651
  }
1139
1652
  ),
1140
- text && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
1653
+ text && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
1141
1654
  ] }) });
1142
1655
  };
1143
1656
  var LoadingSpinner = ({
@@ -1149,7 +1662,7 @@ var LoadingSpinner = ({
1149
1662
  md: "h-8 w-8",
1150
1663
  lg: "h-12 w-12"
1151
1664
  };
1152
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1665
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1153
1666
  "div",
1154
1667
  {
1155
1668
  className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
@@ -1158,9 +1671,9 @@ var LoadingSpinner = ({
1158
1671
  };
1159
1672
 
1160
1673
  // src/components/ui/ErrorBoundary.tsx
1161
- var import_react3 = require("react");
1162
- var import_jsx_runtime5 = require("react/jsx-runtime");
1163
- var ErrorBoundary = class extends import_react3.Component {
1674
+ var import_react6 = require("react");
1675
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1676
+ var ErrorBoundary = class extends import_react6.Component {
1164
1677
  constructor(props) {
1165
1678
  super(props);
1166
1679
  this.handleRetry = () => {
@@ -1182,13 +1695,13 @@ var ErrorBoundary = class extends import_react3.Component {
1182
1695
  if (this.state.hasError) {
1183
1696
  if (this.props.fallback) {
1184
1697
  const FallbackComponent = this.props.fallback;
1185
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
1698
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
1186
1699
  }
1187
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "text-center max-w-md", children: [
1188
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
1189
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
1190
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
1191
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1700
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-center max-w-md", children: [
1701
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
1702
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
1703
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
1704
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1192
1705
  "button",
1193
1706
  {
1194
1707
  onClick: this.handleRetry,
@@ -1202,10 +1715,10 @@ var ErrorBoundary = class extends import_react3.Component {
1202
1715
  return this.props.children;
1203
1716
  }
1204
1717
  };
1205
- var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "text-center", children: [
1206
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
1207
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
1208
- retry && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1718
+ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-center", children: [
1719
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
1720
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
1721
+ retry && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1209
1722
  "button",
1210
1723
  {
1211
1724
  onClick: retry,
@@ -1216,11 +1729,11 @@ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime
1216
1729
  ] }) });
1217
1730
 
1218
1731
  // src/hooks/use-mobile.ts
1219
- var React3 = __toESM(require("react"));
1732
+ var React5 = __toESM(require("react"));
1220
1733
  var MOBILE_BREAKPOINT = 768;
1221
1734
  function useIsMobile() {
1222
- const [isMobile, setIsMobile] = React3.useState(void 0);
1223
- React3.useEffect(() => {
1735
+ const [isMobile, setIsMobile] = React5.useState(void 0);
1736
+ React5.useEffect(() => {
1224
1737
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
1225
1738
  const onChange = () => {
1226
1739
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -1233,9 +1746,9 @@ function useIsMobile() {
1233
1746
  }
1234
1747
 
1235
1748
  // src/hooks/use-local-storage.ts
1236
- var import_react4 = require("react");
1749
+ var import_react7 = require("react");
1237
1750
  function useLocalStorage(key, initialValue) {
1238
- const [storedValue, setStoredValue] = (0, import_react4.useState)(() => {
1751
+ const [storedValue, setStoredValue] = (0, import_react7.useState)(() => {
1239
1752
  try {
1240
1753
  const item = window.localStorage.getItem(key);
1241
1754
  return item ? JSON.parse(item) : initialValue;
@@ -1265,10 +1778,10 @@ function useLocalStorage(key, initialValue) {
1265
1778
  }
1266
1779
 
1267
1780
  // src/hooks/use-debounce.ts
1268
- var import_react5 = require("react");
1781
+ var import_react8 = require("react");
1269
1782
  function useDebounce(value, delay) {
1270
- const [debouncedValue, setDebouncedValue] = (0, import_react5.useState)(value);
1271
- (0, import_react5.useEffect)(() => {
1783
+ const [debouncedValue, setDebouncedValue] = (0, import_react8.useState)(value);
1784
+ (0, import_react8.useEffect)(() => {
1272
1785
  const handler = setTimeout(() => {
1273
1786
  setDebouncedValue(value);
1274
1787
  }, delay);
@@ -1459,18 +1972,48 @@ function injectEarlyErrorHandler() {
1459
1972
  })();
1460
1973
  `;
1461
1974
  try {
1975
+ const parent = document.head || document.documentElement;
1976
+ try {
1977
+ const external = document.createElement("script");
1978
+ external.type = "text/javascript";
1979
+ external.src = "/error-handler.js";
1980
+ external.async = false;
1981
+ parent.prepend(external);
1982
+ return;
1983
+ } catch (e) {
1984
+ void e;
1985
+ }
1462
1986
  const script = document.createElement("script");
1463
1987
  script.type = "text/javascript";
1464
- script.text = code;
1465
- const parent = document.head || document.documentElement;
1988
+ try {
1989
+ if ("textContent" in script) {
1990
+ script.textContent = code;
1991
+ } else {
1992
+ script.appendChild(document.createTextNode(code));
1993
+ }
1994
+ } catch (e) {
1995
+ try {
1996
+ script.appendChild(document.createTextNode(code));
1997
+ } catch {
1998
+ }
1999
+ }
1466
2000
  parent.prepend(script);
1467
2001
  } catch (e) {
1468
2002
  void e;
1469
2003
  }
1470
2004
  }
2005
+
2006
+ // src/index.ts
2007
+ init_config();
2008
+ init_config();
1471
2009
  // Annotate the CommonJS export names for ESM import in node:
1472
2010
  0 && (module.exports = {
2011
+ AUTH_ROOT,
2012
+ AUTH_TOKEN_KEY,
1473
2013
  AuthGuard,
2014
+ AuthProvider,
2015
+ AuthRedirector,
2016
+ AuthRedirectorDefault,
1474
2017
  DefaultErrorFallback,
1475
2018
  ErrorBoundary,
1476
2019
  FloatingButton,
@@ -1484,13 +2027,25 @@ function injectEarlyErrorHandler() {
1484
2027
  createAIWorkflowClientAxios,
1485
2028
  createArtifactsClient,
1486
2029
  createClient,
2030
+ getAuthRoot,
1487
2031
  getCodeStatus,
2032
+ getDefaultProjectId,
2033
+ getToken,
2034
+ howone,
1488
2035
  injectEarlyErrorHandler,
2036
+ isTokenValid,
1489
2037
  loginWithEmailCode,
2038
+ onAuthStateChanged,
2039
+ parseUserFromToken,
1490
2040
  request,
1491
2041
  sendEmailVerificationCode,
2042
+ setAuthRoot,
2043
+ setDefaultProjectId,
2044
+ setToken,
1492
2045
  unifiedAuth,
1493
2046
  unifiedOAuth,
2047
+ useAuth,
2048
+ useAuthContext,
1494
2049
  useDebounce,
1495
2050
  useIsMobile,
1496
2051
  useLocalStorage,