openxiangda 1.0.83 → 1.0.85

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.
@@ -1,11 +1,11 @@
1
1
  // packages/sdk/src/runtime/react/openxiangdaProvider.tsx
2
2
  import {
3
3
  createContext,
4
- useCallback,
4
+ useCallback as useCallback2,
5
5
  useContext,
6
- useEffect,
7
- useMemo,
8
- useState
6
+ useEffect as useEffect2,
7
+ useMemo as useMemo2,
8
+ useState as useState2
9
9
  } from "react";
10
10
 
11
11
  // packages/sdk/src/runtime/core/fetch.ts
@@ -14,8 +14,631 @@ var createBoundFetch = (fetchImpl) => {
14
14
  return ((input, init) => baseFetch.call(globalThis, input, init));
15
15
  };
16
16
 
17
+ // packages/sdk/src/runtime/react/auth.tsx
18
+ import {
19
+ useCallback,
20
+ useEffect,
21
+ useMemo,
22
+ useState
23
+ } from "react";
24
+ import {
25
+ Alert,
26
+ Button,
27
+ Card,
28
+ Empty,
29
+ Form,
30
+ Input,
31
+ Space,
32
+ Tabs,
33
+ Typography
34
+ } from "antd";
35
+ import {
36
+ LoginOutlined,
37
+ MobileOutlined,
38
+ QrcodeOutlined,
39
+ SafetyCertificateOutlined,
40
+ UserOutlined
41
+ } from "@ant-design/icons";
42
+
43
+ // packages/sdk/src/runtime/core/auth.ts
44
+ var AuthClientError = class extends Error {
45
+ constructor(message, options = {}) {
46
+ super(message);
47
+ this.name = "AuthClientError";
48
+ this.status = options.status;
49
+ this.code = options.code;
50
+ this.payload = options.payload;
51
+ }
52
+ };
53
+ var createAuthClient = ({
54
+ appType,
55
+ servicePrefix = "/service",
56
+ fetchImpl
57
+ }) => {
58
+ const normalizedAppType = String(appType || "").trim();
59
+ if (!normalizedAppType) {
60
+ throw new Error("appType \u4E0D\u80FD\u4E3A\u7A7A");
61
+ }
62
+ const boundFetch = createBoundFetch(fetchImpl);
63
+ const request = async (path, options = {}) => {
64
+ const response = await boundFetch(buildServiceUrl(servicePrefix, path), {
65
+ credentials: "include",
66
+ ...options,
67
+ headers: {
68
+ accept: "application/json",
69
+ ...options.body ? { "content-type": "application/json" } : {},
70
+ ...options.headers || {}
71
+ }
72
+ });
73
+ const payload = await readPayload(response);
74
+ const code = getRecordValue(payload, "code");
75
+ if (!response.ok || typeof code === "number" && code >= 400) {
76
+ throw new AuthClientError(
77
+ String(getRecordValue(payload, "message") || `Auth request failed: ${response.status}`),
78
+ { status: response.status, code, payload }
79
+ );
80
+ }
81
+ return unwrapPayload(payload);
82
+ };
83
+ const appAuthPath = (suffix) => `/openxiangda-api/v1/apps/${encodeURIComponent(normalizedAppType)}/auth${suffix}`;
84
+ return {
85
+ appType: normalizedAppType,
86
+ servicePrefix,
87
+ getMethods: () => request(appAuthPath("/methods")),
88
+ passwordLogin: (input) => request(appAuthPath("/password/login"), postJson(input)),
89
+ dingtalkLogin: (input) => request(appAuthPath("/dingtalk/login"), postJson(input)),
90
+ guestLogin: (input) => request(appAuthPath("/guest/login"), postJson(input || {})),
91
+ sendPhoneCode: (input) => request(appAuthPath("/phone-code/send"), postJson(input)),
92
+ phoneCodeLogin: (input) => request(appAuthPath("/phone-code/login"), postJson(input)),
93
+ registerWithPhoneCode: (input) => request(appAuthPath("/phone-code/register"), postJson(input)),
94
+ getSsoLoginUrl: (input) => request(appAuthPath("/sso/login-url"), postJson(input || {})),
95
+ refresh: (input) => request(appAuthPath("/refresh"), postJson(input || {})),
96
+ logout: async () => {
97
+ await request(appAuthPath("/logout"), { method: "POST" });
98
+ },
99
+ resolveLoginUrl: (input) => resolveLoginUrl(normalizedAppType, input || {})
100
+ };
101
+ };
102
+ var postJson = (body) => ({
103
+ method: "POST",
104
+ body: JSON.stringify(body || {})
105
+ });
106
+ var buildServiceUrl = (servicePrefix, path) => {
107
+ const prefix = servicePrefix.endsWith("/") ? servicePrefix.slice(0, -1) : servicePrefix;
108
+ const suffix = path.startsWith("/") ? path : `/${path}`;
109
+ return `${prefix}${suffix}`;
110
+ };
111
+ var readPayload = async (response) => {
112
+ try {
113
+ return await response.json();
114
+ } catch {
115
+ return null;
116
+ }
117
+ };
118
+ var unwrapPayload = (payload) => {
119
+ if (!payload || typeof payload !== "object") return payload;
120
+ const record = payload;
121
+ if ("data" in record) return record.data;
122
+ return payload;
123
+ };
124
+ var getRecordValue = (value, key) => {
125
+ if (!value || typeof value !== "object") return void 0;
126
+ return value[key];
127
+ };
128
+ var resolveLoginUrl = (appType, {
129
+ callbackUrl = getCurrentHref(),
130
+ callbackParamName = "callback",
131
+ loginUrl
132
+ }) => {
133
+ const target = loginUrl || `/view/${encodeURIComponent(appType)}/login`;
134
+ if (!callbackUrl) return target;
135
+ try {
136
+ const base = typeof window !== "undefined" ? window.location.origin : "http://localhost";
137
+ const url = new URL(target, base);
138
+ if (!url.searchParams.has(callbackParamName)) {
139
+ url.searchParams.set(callbackParamName, callbackUrl);
140
+ }
141
+ if (target.startsWith("http://") || target.startsWith("https://")) {
142
+ return url.toString();
143
+ }
144
+ return `${url.pathname}${url.search}${url.hash}`;
145
+ } catch {
146
+ const separator = target.includes("?") ? "&" : "?";
147
+ return `${target}${separator}${callbackParamName}=${encodeURIComponent(callbackUrl)}`;
148
+ }
149
+ };
150
+ var getCurrentHref = () => typeof window === "undefined" ? "" : window.location.href;
151
+
152
+ // packages/sdk/src/runtime/react/auth.tsx
153
+ import { jsx, jsxs } from "react/jsx-runtime";
154
+ var useAuth = (options = {}) => {
155
+ const runtime = useOpenXiangda();
156
+ const client = useMemo(
157
+ () => createAuthClient({
158
+ appType: options.appType || runtime.appType,
159
+ servicePrefix: options.servicePrefix || runtime.servicePrefix,
160
+ fetchImpl: options.fetchImpl || runtime.fetchImpl
161
+ }),
162
+ [
163
+ options.appType,
164
+ options.fetchImpl,
165
+ options.servicePrefix,
166
+ runtime.appType,
167
+ runtime.fetchImpl,
168
+ runtime.servicePrefix
169
+ ]
170
+ );
171
+ return useMemo(
172
+ () => ({
173
+ client,
174
+ getMethods: client.getMethods,
175
+ passwordLogin: client.passwordLogin,
176
+ dingtalkLogin: client.dingtalkLogin,
177
+ guestLogin: client.guestLogin,
178
+ sendPhoneCode: client.sendPhoneCode,
179
+ phoneCodeLogin: client.phoneCodeLogin,
180
+ registerWithPhoneCode: client.registerWithPhoneCode,
181
+ getSsoLoginUrl: client.getSsoLoginUrl,
182
+ refresh: client.refresh,
183
+ logout: client.logout,
184
+ resolveLoginUrl: client.resolveLoginUrl
185
+ }),
186
+ [client]
187
+ );
188
+ };
189
+ var useLoginMethods = (options = {}) => {
190
+ const auth = useAuth(options);
191
+ const [state, setState] = useState({
192
+ data: null,
193
+ loading: true,
194
+ error: null
195
+ });
196
+ const reload = useCallback(async () => {
197
+ setState((prev) => ({ ...prev, loading: true, error: null }));
198
+ try {
199
+ const data = await auth.getMethods();
200
+ setState({ data, loading: false, error: null });
201
+ } catch (error) {
202
+ setState({
203
+ data: null,
204
+ loading: false,
205
+ error: normalizeError(error)
206
+ });
207
+ }
208
+ }, [auth]);
209
+ useEffect(() => {
210
+ let disposed = false;
211
+ const run = async () => {
212
+ setState((prev) => ({ ...prev, loading: true, error: null }));
213
+ try {
214
+ const data = await auth.getMethods();
215
+ if (!disposed) setState({ data, loading: false, error: null });
216
+ } catch (error) {
217
+ if (!disposed) {
218
+ setState({
219
+ data: null,
220
+ loading: false,
221
+ error: normalizeError(error)
222
+ });
223
+ }
224
+ }
225
+ };
226
+ void run();
227
+ return () => {
228
+ disposed = true;
229
+ };
230
+ }, [auth]);
231
+ return {
232
+ ...state,
233
+ methods: state.data?.methods || [],
234
+ reload
235
+ };
236
+ };
237
+ var LoginPage = ({
238
+ title,
239
+ subtitle,
240
+ className,
241
+ style,
242
+ defaultMethod,
243
+ redirectUrl,
244
+ redirectOnSuccess = true,
245
+ onSuccess,
246
+ ...authOptions
247
+ }) => {
248
+ const runtime = useOpenXiangda();
249
+ const auth = useAuth(authOptions);
250
+ const methodsState = useLoginMethods(authOptions);
251
+ const [passwordForm] = Form.useForm();
252
+ const [phoneForm] = Form.useForm();
253
+ const [activeMethod, setActiveMethod] = useState(
254
+ defaultMethod || "password"
255
+ );
256
+ const [phonePurpose, setPhonePurpose] = useState(
257
+ "login"
258
+ );
259
+ const [phoneChallengeId, setPhoneChallengeId] = useState("");
260
+ const [submitting, setSubmitting] = useState(false);
261
+ const [sendingCode, setSendingCode] = useState(false);
262
+ const [error, setError] = useState(null);
263
+ const methods = methodsState.methods.filter((method) => method.enabled !== false);
264
+ const passwordMethod = findMethod(methods, "password");
265
+ const phoneMethod = findMethod(methods, "phone_code");
266
+ const dingtalkMethod = findMethod(methods, "dingtalk");
267
+ const ssoMethod = findMethod(methods, "sso");
268
+ const guestMethod = findMethod(methods, "guest");
269
+ const allowRegister = methodsState.data?.registration?.mode !== "reject";
270
+ const tabItems = useMemo(() => {
271
+ const items = [];
272
+ if (passwordMethod) {
273
+ items.push({
274
+ key: "password",
275
+ label: /* @__PURE__ */ jsxs(Space, { size: 6, children: [
276
+ /* @__PURE__ */ jsx(UserOutlined, {}),
277
+ /* @__PURE__ */ jsx("span", { children: passwordMethod.label || "\u8D26\u53F7\u5BC6\u7801" })
278
+ ] }),
279
+ children: /* @__PURE__ */ jsx(
280
+ PasswordLoginForm,
281
+ {
282
+ form: passwordForm,
283
+ loading: submitting,
284
+ onFinish: async (values) => {
285
+ setSubmitting(true);
286
+ setError(null);
287
+ try {
288
+ await handleSuccess(
289
+ await auth.passwordLogin({
290
+ username: values.username,
291
+ password: values.password
292
+ })
293
+ );
294
+ } catch (loginError) {
295
+ setError(normalizeError(loginError).message);
296
+ } finally {
297
+ setSubmitting(false);
298
+ }
299
+ }
300
+ }
301
+ )
302
+ });
303
+ }
304
+ if (phoneMethod) {
305
+ items.push({
306
+ key: "phone_code",
307
+ label: /* @__PURE__ */ jsxs(Space, { size: 6, children: [
308
+ /* @__PURE__ */ jsx(MobileOutlined, {}),
309
+ /* @__PURE__ */ jsx("span", { children: phoneMethod.label || "\u624B\u673A\u53F7" })
310
+ ] }),
311
+ children: /* @__PURE__ */ jsx(
312
+ PhoneCodeLoginForm,
313
+ {
314
+ allowRegister,
315
+ form: phoneForm,
316
+ loading: submitting,
317
+ phonePurpose,
318
+ sendingCode,
319
+ onPurposeChange: setPhonePurpose,
320
+ onSendCode: async () => {
321
+ const values = await phoneForm.validateFields(["phone"]);
322
+ setSendingCode(true);
323
+ setError(null);
324
+ try {
325
+ const result = await auth.sendPhoneCode({
326
+ phone: values.phone,
327
+ purpose: phonePurpose
328
+ });
329
+ setPhoneChallengeId(result.challengeId);
330
+ } catch (sendError) {
331
+ setError(normalizeError(sendError).message);
332
+ } finally {
333
+ setSendingCode(false);
334
+ }
335
+ },
336
+ onFinish: async (values) => {
337
+ setSubmitting(true);
338
+ setError(null);
339
+ try {
340
+ const data = phonePurpose === "register" ? await auth.registerWithPhoneCode({
341
+ phone: values.phone,
342
+ code: values.code,
343
+ challengeId: phoneChallengeId
344
+ }) : await auth.phoneCodeLogin({
345
+ phone: values.phone,
346
+ code: values.code,
347
+ challengeId: phoneChallengeId
348
+ });
349
+ await handleSuccess(data);
350
+ } catch (loginError) {
351
+ setError(normalizeError(loginError).message);
352
+ } finally {
353
+ setSubmitting(false);
354
+ }
355
+ }
356
+ }
357
+ )
358
+ });
359
+ }
360
+ return items;
361
+ }, [
362
+ allowRegister,
363
+ auth,
364
+ handleSuccess,
365
+ passwordForm,
366
+ passwordMethod,
367
+ phoneChallengeId,
368
+ phoneForm,
369
+ phoneMethod,
370
+ phonePurpose,
371
+ sendingCode,
372
+ submitting
373
+ ]);
374
+ useEffect(() => {
375
+ const firstKey = tabItems[0]?.key;
376
+ if (firstKey && !tabItems.some((item) => item.key === activeMethod)) {
377
+ setActiveMethod(firstKey);
378
+ }
379
+ }, [activeMethod, tabItems]);
380
+ const handleDingTalkLogin = async () => {
381
+ setSubmitting(true);
382
+ setError(null);
383
+ try {
384
+ const code = await requestDingTalkCode(dingtalkMethod);
385
+ await handleSuccess(
386
+ await auth.dingtalkLogin({
387
+ code,
388
+ corpId: getString(dingtalkMethod, "corpId")
389
+ })
390
+ );
391
+ } catch (loginError) {
392
+ setError(normalizeError(loginError).message);
393
+ } finally {
394
+ setSubmitting(false);
395
+ }
396
+ };
397
+ const handleSsoLogin = async () => {
398
+ setSubmitting(true);
399
+ setError(null);
400
+ try {
401
+ const redirectUri = getCurrentHref2();
402
+ const result = await auth.getSsoLoginUrl({
403
+ protocol: getString(ssoMethod, "protocol") || "cas",
404
+ redirectUri
405
+ });
406
+ window.location.assign(result.loginUrl);
407
+ } catch (loginError) {
408
+ setError(normalizeError(loginError).message);
409
+ setSubmitting(false);
410
+ }
411
+ };
412
+ const handleGuestLogin = async () => {
413
+ setSubmitting(true);
414
+ setError(null);
415
+ try {
416
+ await handleSuccess(
417
+ await auth.guestLogin({
418
+ guestIdentifier: getOrCreateGuestIdentifier(auth.client),
419
+ domain: getCurrentHostname()
420
+ })
421
+ );
422
+ } catch (loginError) {
423
+ setError(normalizeError(loginError).message);
424
+ } finally {
425
+ setSubmitting(false);
426
+ }
427
+ };
428
+ async function handleSuccess(data) {
429
+ await onSuccess?.(data);
430
+ await runtime.reload();
431
+ if (redirectOnSuccess && typeof window !== "undefined") {
432
+ window.location.replace(
433
+ redirectUrl || getCallbackUrl() || `/view/${auth.client.appType}`
434
+ );
435
+ }
436
+ }
437
+ return /* @__PURE__ */ jsx(
438
+ "div",
439
+ {
440
+ className,
441
+ style: {
442
+ minHeight: "100vh",
443
+ display: "grid",
444
+ placeItems: "center",
445
+ padding: 24,
446
+ background: "#f6f8fb",
447
+ ...style
448
+ },
449
+ children: /* @__PURE__ */ jsx(
450
+ Card,
451
+ {
452
+ style: {
453
+ width: "min(100%, 420px)",
454
+ borderRadius: 8,
455
+ boxShadow: "0 16px 48px rgba(15, 23, 42, 0.10)"
456
+ },
457
+ styles: { body: { padding: 28 } },
458
+ children: /* @__PURE__ */ jsxs(Space, { direction: "vertical", size: 20, style: { width: "100%" }, children: [
459
+ /* @__PURE__ */ jsxs("div", { children: [
460
+ /* @__PURE__ */ jsx(Typography.Title, { level: 3, style: { margin: 0 }, children: title || "\u5E94\u7528\u767B\u5F55" }),
461
+ subtitle ? /* @__PURE__ */ jsx(Typography.Text, { type: "secondary", children: subtitle }) : null
462
+ ] }),
463
+ methodsState.error ? /* @__PURE__ */ jsx(
464
+ Alert,
465
+ {
466
+ showIcon: true,
467
+ type: "error",
468
+ message: methodsState.error.message
469
+ }
470
+ ) : null,
471
+ error ? /* @__PURE__ */ jsx(Alert, { showIcon: true, type: "error", message: error }) : null,
472
+ methodsState.loading ? /* @__PURE__ */ jsx(Button, { block: true, loading: true, children: "\u52A0\u8F7D\u4E2D" }) : tabItems.length > 0 ? /* @__PURE__ */ jsx(
473
+ Tabs,
474
+ {
475
+ activeKey: activeMethod,
476
+ items: tabItems,
477
+ onChange: setActiveMethod
478
+ }
479
+ ) : /* @__PURE__ */ jsx(Empty, { description: "\u672A\u542F\u7528\u767B\u5F55\u65B9\u5F0F" }),
480
+ /* @__PURE__ */ jsxs(Space, { direction: "vertical", size: 10, style: { width: "100%" }, children: [
481
+ dingtalkMethod ? /* @__PURE__ */ jsx(
482
+ Button,
483
+ {
484
+ block: true,
485
+ icon: /* @__PURE__ */ jsx(QrcodeOutlined, {}),
486
+ loading: submitting,
487
+ onClick: handleDingTalkLogin,
488
+ children: dingtalkMethod.label || "\u9489\u9489\u514D\u767B"
489
+ }
490
+ ) : null,
491
+ ssoMethod ? /* @__PURE__ */ jsx(
492
+ Button,
493
+ {
494
+ block: true,
495
+ icon: /* @__PURE__ */ jsx(SafetyCertificateOutlined, {}),
496
+ loading: submitting,
497
+ onClick: handleSsoLogin,
498
+ children: ssoMethod.label || "SSO \u767B\u5F55"
499
+ }
500
+ ) : null,
501
+ guestMethod ? /* @__PURE__ */ jsx(
502
+ Button,
503
+ {
504
+ block: true,
505
+ icon: /* @__PURE__ */ jsx(LoginOutlined, {}),
506
+ loading: submitting,
507
+ onClick: handleGuestLogin,
508
+ children: guestMethod.label || "\u8BBF\u5BA2\u8BBF\u95EE"
509
+ }
510
+ ) : null
511
+ ] })
512
+ ] })
513
+ }
514
+ )
515
+ }
516
+ );
517
+ };
518
+ var PasswordLoginForm = ({ form, loading, onFinish }) => /* @__PURE__ */ jsxs(Form, { form, layout: "vertical", requiredMark: false, onFinish, children: [
519
+ /* @__PURE__ */ jsx(
520
+ Form.Item,
521
+ {
522
+ label: "\u8D26\u53F7",
523
+ name: "username",
524
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u8D26\u53F7" }],
525
+ children: /* @__PURE__ */ jsx(Input, { autoComplete: "username" })
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsx(
529
+ Form.Item,
530
+ {
531
+ label: "\u5BC6\u7801",
532
+ name: "password",
533
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u5BC6\u7801" }],
534
+ children: /* @__PURE__ */ jsx(Input.Password, { autoComplete: "current-password" })
535
+ }
536
+ ),
537
+ /* @__PURE__ */ jsx(Button, { block: true, htmlType: "submit", icon: /* @__PURE__ */ jsx(LoginOutlined, {}), loading, type: "primary", children: "\u767B\u5F55" })
538
+ ] });
539
+ var PhoneCodeLoginForm = ({
540
+ allowRegister,
541
+ form,
542
+ loading,
543
+ phonePurpose,
544
+ sendingCode,
545
+ onPurposeChange,
546
+ onSendCode,
547
+ onFinish
548
+ }) => /* @__PURE__ */ jsxs(Form, { form, layout: "vertical", requiredMark: false, onFinish, children: [
549
+ allowRegister ? /* @__PURE__ */ jsx(Form.Item, { style: { marginBottom: 12 }, children: /* @__PURE__ */ jsx(
550
+ Tabs,
551
+ {
552
+ activeKey: phonePurpose,
553
+ items: [
554
+ { key: "login", label: "\u767B\u5F55" },
555
+ { key: "register", label: "\u6CE8\u518C" }
556
+ ],
557
+ onChange: (key) => onPurposeChange(key === "register" ? "register" : "login"),
558
+ size: "small"
559
+ }
560
+ ) }) : null,
561
+ /* @__PURE__ */ jsx(
562
+ Form.Item,
563
+ {
564
+ label: "\u624B\u673A\u53F7",
565
+ name: "phone",
566
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u624B\u673A\u53F7" }],
567
+ children: /* @__PURE__ */ jsx(Input, { autoComplete: "tel" })
568
+ }
569
+ ),
570
+ /* @__PURE__ */ jsx(
571
+ Form.Item,
572
+ {
573
+ label: "\u9A8C\u8BC1\u7801",
574
+ name: "code",
575
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801" }],
576
+ children: /* @__PURE__ */ jsx(
577
+ Input,
578
+ {
579
+ addonAfter: /* @__PURE__ */ jsx(
580
+ Button,
581
+ {
582
+ loading: sendingCode,
583
+ onClick: onSendCode,
584
+ size: "small",
585
+ type: "link",
586
+ children: "\u53D1\u9001"
587
+ }
588
+ ),
589
+ autoComplete: "one-time-code"
590
+ }
591
+ )
592
+ }
593
+ ),
594
+ /* @__PURE__ */ jsx(Button, { block: true, htmlType: "submit", icon: /* @__PURE__ */ jsx(MobileOutlined, {}), loading, type: "primary", children: phonePurpose === "register" ? "\u6CE8\u518C" : "\u767B\u5F55" })
595
+ ] });
596
+ var findMethod = (methods, type) => methods.find((method) => method.type === type);
597
+ var normalizeError = (error) => error instanceof Error ? error : new Error(String(error || "\u8BF7\u6C42\u5931\u8D25"));
598
+ var getString = (value, key) => {
599
+ if (!value || typeof value !== "object") return void 0;
600
+ const result = value[key];
601
+ return typeof result === "string" ? result : void 0;
602
+ };
603
+ var requestDingTalkCode = (method) => {
604
+ const dd = typeof window === "undefined" ? void 0 : window.dd;
605
+ const corpId = getString(method, "corpId");
606
+ return new Promise((resolve, reject) => {
607
+ const requestAuthCode = dd?.runtime?.permission?.requestAuthCode || dd?.requestAuthCode;
608
+ if (!requestAuthCode) {
609
+ reject(new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u9489\u9489\u514D\u767B"));
610
+ return;
611
+ }
612
+ requestAuthCode({
613
+ corpId,
614
+ onSuccess: (result) => {
615
+ if (result?.code) resolve(result.code);
616
+ else reject(new Error("\u9489\u9489\u672A\u8FD4\u56DE\u514D\u767B\u7801"));
617
+ },
618
+ onFail: (error) => reject(normalizeError(error))
619
+ });
620
+ });
621
+ };
622
+ var getOrCreateGuestIdentifier = (client) => {
623
+ const key = `openxiangda:${client.appType}:guest_id`;
624
+ if (typeof window === "undefined") return createGuestIdentifier();
625
+ const current = window.localStorage.getItem(key);
626
+ if (current) return current;
627
+ const next = createGuestIdentifier();
628
+ window.localStorage.setItem(key, next);
629
+ return next;
630
+ };
631
+ var createGuestIdentifier = () => `guest_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
632
+ var getCurrentHref2 = () => typeof window === "undefined" ? "" : window.location.href;
633
+ var getCurrentHostname = () => typeof window === "undefined" ? "" : window.location.hostname;
634
+ var getCallbackUrl = () => {
635
+ if (typeof window === "undefined") return "";
636
+ const query = new URLSearchParams(window.location.search);
637
+ return query.get("callback") || query.get("redirectUri") || "";
638
+ };
639
+
17
640
  // packages/sdk/src/runtime/react/openxiangdaProvider.tsx
18
- import { Fragment, jsx } from "react/jsx-runtime";
641
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
19
642
  var RuntimeHttpError = class extends Error {
20
643
  constructor(snapshot) {
21
644
  super(snapshot.message);
@@ -33,17 +656,17 @@ var OpenXiangdaProvider = ({
33
656
  fetchImpl,
34
657
  children
35
658
  }) => {
36
- const resolvedFetch = useMemo(() => createBoundFetch(fetchImpl), [fetchImpl]);
37
- const resolvedAppType = useMemo(
659
+ const resolvedFetch = useMemo2(() => createBoundFetch(fetchImpl), [fetchImpl]);
660
+ const resolvedAppType = useMemo2(
38
661
  () => appType || resolveAppTypeFromLocation(),
39
662
  [appType]
40
663
  );
41
- const [state, setState] = useState({
664
+ const [state, setState] = useState2({
42
665
  data: null,
43
666
  loading: true,
44
667
  error: null
45
668
  });
46
- const reload = useCallback(async () => {
669
+ const reload = useCallback2(async () => {
47
670
  if (!resolvedAppType) {
48
671
  setState({
49
672
  data: null,
@@ -58,7 +681,7 @@ var OpenXiangdaProvider = ({
58
681
  setState((prev) => ({ ...prev, loading: true, error: null }));
59
682
  try {
60
683
  const response = await resolvedFetch(
61
- buildServiceUrl(
684
+ buildServiceUrl2(
62
685
  servicePrefix,
63
686
  `/openxiangda-api/v1/apps/${encodeURIComponent(
64
687
  resolvedAppType
@@ -90,10 +713,10 @@ var OpenXiangdaProvider = ({
90
713
  });
91
714
  }
92
715
  }, [resolvedAppType, resolvedFetch, servicePrefix]);
93
- useEffect(() => {
716
+ useEffect2(() => {
94
717
  void reload();
95
718
  }, [reload]);
96
- const value = useMemo(
719
+ const value = useMemo2(
97
720
  () => ({
98
721
  ...state,
99
722
  appType: resolvedAppType,
@@ -103,7 +726,7 @@ var OpenXiangdaProvider = ({
103
726
  }),
104
727
  [reload, resolvedAppType, resolvedFetch, servicePrefix, state]
105
728
  );
106
- return /* @__PURE__ */ jsx(OpenXiangdaRuntimeContext.Provider, { value, children });
729
+ return /* @__PURE__ */ jsx2(OpenXiangdaRuntimeContext.Provider, { value, children });
107
730
  };
108
731
  var useOpenXiangda = () => {
109
732
  const context = useContext(OpenXiangdaRuntimeContext);
@@ -129,12 +752,12 @@ var usePermission = () => {
129
752
  };
130
753
  var useCanAccessRoute = (input) => {
131
754
  const runtime = useOpenXiangda();
132
- const [state, setState] = useState({
755
+ const [state, setState] = useState2({
133
756
  data: null,
134
757
  loading: true,
135
758
  error: null
136
759
  });
137
- useEffect(() => {
760
+ useEffect2(() => {
138
761
  let disposed = false;
139
762
  const check = async () => {
140
763
  const permissions = runtime.data?.permissions;
@@ -170,7 +793,7 @@ var useCanAccessRoute = (input) => {
170
793
  setState((prev) => ({ ...prev, loading: true, error: null }));
171
794
  try {
172
795
  const response = await runtime.fetchImpl(
173
- buildServiceUrl(
796
+ buildServiceUrl2(
174
797
  runtime.servicePrefix,
175
798
  `/openxiangda-api/v1/apps/${encodeURIComponent(
176
799
  runtime.appType
@@ -256,23 +879,23 @@ var PermissionBoundary = ({
256
879
  const access = useCanAccessRoute({ routeCode, menuCode, path });
257
880
  const fallbackState = createPermissionFallbackState(access, runtime);
258
881
  if (access.loading) {
259
- return /* @__PURE__ */ jsx(Fragment, { children: renderBoundaryFallback(loadingFallback, fallbackState) });
882
+ return /* @__PURE__ */ jsx2(Fragment, { children: renderBoundaryFallback(loadingFallback, fallbackState) });
260
883
  }
261
884
  if (!access.canAccess) {
262
- return /* @__PURE__ */ jsx(Fragment, { children: renderBoundaryFallback(fallback, fallbackState) });
885
+ return /* @__PURE__ */ jsx2(Fragment, { children: renderBoundaryFallback(fallback, fallbackState) });
263
886
  }
264
- return /* @__PURE__ */ jsx(Fragment, { children });
887
+ return /* @__PURE__ */ jsx2(Fragment, { children });
265
888
  };
266
889
  var useRuntimeAuth = () => {
267
890
  const runtime = useOpenXiangda();
268
- const resolveLoginUrl = useCallback(
891
+ const resolveLoginUrl2 = useCallback2(
269
892
  async (options = {}) => {
270
- const redirectUri = options.redirectUri || getCurrentHref();
271
- const domain = options.domain || getCurrentHostname();
893
+ const redirectUri = options.redirectUri || getCurrentHref3();
894
+ const domain = options.domain || getCurrentHostname2();
272
895
  const appTenantId = getRecordString(runtime.data?.app, "tenantId");
273
896
  try {
274
897
  const statusUrl = withQuery(
275
- buildServiceUrl(runtime.servicePrefix, "/api/sso/status"),
898
+ buildServiceUrl2(runtime.servicePrefix, "/api/sso/status"),
276
899
  { domain }
277
900
  );
278
901
  const statusResponse = await runtime.fetchImpl(statusUrl, {
@@ -287,7 +910,7 @@ var useRuntimeAuth = () => {
287
910
  );
288
911
  if (shouldUseSso) {
289
912
  const loginUrlResponse = await runtime.fetchImpl(
290
- withQuery(buildServiceUrl(runtime.servicePrefix, "/api/sso/login-url"), {
913
+ withQuery(buildServiceUrl2(runtime.servicePrefix, "/api/sso/login-url"), {
291
914
  domain,
292
915
  redirectUri,
293
916
  ...sso.tenantId || appTenantId ? { tenantId: String(sso.tenantId || appTenantId) } : {},
@@ -312,9 +935,9 @@ var useRuntimeAuth = () => {
312
935
  },
313
936
  [runtime.data?.app, runtime.fetchImpl, runtime.servicePrefix]
314
937
  );
315
- const redirectToLogin = useCallback(
938
+ const redirectToLogin = useCallback2(
316
939
  async (options = {}) => {
317
- const loginUrl = await resolveLoginUrl(options);
940
+ const loginUrl = await resolveLoginUrl2(options);
318
941
  if (typeof window !== "undefined") {
319
942
  if (options.replace === false) {
320
943
  window.location.assign(loginUrl);
@@ -324,11 +947,11 @@ var useRuntimeAuth = () => {
324
947
  }
325
948
  return loginUrl;
326
949
  },
327
- [resolveLoginUrl]
950
+ [resolveLoginUrl2]
328
951
  );
329
- const logout = useCallback(async () => {
952
+ const logout = useCallback2(async () => {
330
953
  const response = await runtime.fetchImpl(
331
- buildServiceUrl(runtime.servicePrefix, "/api/auth/logout"),
954
+ buildServiceUrl2(runtime.servicePrefix, "/api/auth/logout"),
332
955
  {
333
956
  method: "POST",
334
957
  credentials: "include",
@@ -345,7 +968,7 @@ var useRuntimeAuth = () => {
345
968
  }
346
969
  return payload;
347
970
  }, [runtime.fetchImpl, runtime.servicePrefix]);
348
- const logoutAndRedirect = useCallback(
971
+ const logoutAndRedirect = useCallback2(
349
972
  async (options = {}) => {
350
973
  try {
351
974
  await logout();
@@ -360,10 +983,10 @@ var useRuntimeAuth = () => {
360
983
  logout,
361
984
  logoutAndRedirect,
362
985
  redirectToLogin,
363
- resolveLoginUrl
986
+ resolveLoginUrl: resolveLoginUrl2
364
987
  };
365
988
  };
366
- var buildServiceUrl = (servicePrefix, path) => {
989
+ var buildServiceUrl2 = (servicePrefix, path) => {
367
990
  const prefix = servicePrefix.endsWith("/") ? servicePrefix.slice(0, -1) : servicePrefix;
368
991
  const suffix = path.startsWith("/") ? path : `/${path}`;
369
992
  return `${prefix}${suffix}`;
@@ -378,11 +1001,11 @@ var readJsonPayload = async (response) => {
378
1001
  var createRuntimeHttpError = (response, payload, fallbackMessage) => createRuntimeError({
379
1002
  type: classifyRuntimeError(
380
1003
  response.status,
381
- getRecordValue(payload, "code")
1004
+ getRecordValue2(payload, "code")
382
1005
  ),
383
1006
  status: response.status,
384
- code: getRecordValue(payload, "code"),
385
- message: getRecordValue(payload, "message") || fallbackMessage,
1007
+ code: getRecordValue2(payload, "code"),
1008
+ message: getRecordValue2(payload, "message") || fallbackMessage,
386
1009
  payload
387
1010
  });
388
1011
  var createRuntimeError = (snapshot) => new RuntimeHttpError({
@@ -458,18 +1081,18 @@ var attachCallback = (loginUrl, callback) => {
458
1081
  return `${loginUrl}${separator}callback=${encodeURIComponent(callback)}`;
459
1082
  }
460
1083
  };
461
- var getCurrentHref = () => typeof window === "undefined" ? "" : window.location.href;
462
- var getCurrentHostname = () => typeof window === "undefined" ? "" : window.location.hostname;
1084
+ var getCurrentHref3 = () => typeof window === "undefined" ? "" : window.location.href;
1085
+ var getCurrentHostname2 = () => typeof window === "undefined" ? "" : window.location.hostname;
463
1086
  var getRuntimeEnv = (key) => {
464
1087
  const env = typeof process !== "undefined" ? process.env : void 0;
465
1088
  return env?.[key];
466
1089
  };
467
- var getRecordValue = (value, key) => {
1090
+ var getRecordValue2 = (value, key) => {
468
1091
  if (!value || typeof value !== "object") return void 0;
469
1092
  return value[key];
470
1093
  };
471
1094
  var getRecordString = (value, key) => {
472
- const result = getRecordValue(value, key);
1095
+ const result = getRecordValue2(value, key);
473
1096
  return typeof result === "string" ? result : void 0;
474
1097
  };
475
1098
  var resolveAppTypeFromLocation = () => {
@@ -481,11 +1104,16 @@ var resolveAppTypeFromLocation = () => {
481
1104
  return segments[viewIndex] || "";
482
1105
  };
483
1106
  export {
1107
+ AuthClientError,
1108
+ LoginPage,
484
1109
  OpenXiangdaProvider,
485
1110
  PermissionBoundary,
486
1111
  RuntimeHttpError,
1112
+ createAuthClient,
487
1113
  useAppMenus,
1114
+ useAuth,
488
1115
  useCanAccessRoute,
1116
+ useLoginMethods,
489
1117
  useOpenXiangda,
490
1118
  usePermission,
491
1119
  useRuntimeAuth,