openxiangda 1.0.159 → 1.0.160
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 +1 -1
- package/lib/cli.js +7 -0
- package/openxiangda-skills/SKILL.md +2 -1
- package/openxiangda-skills/references/architecture-design.md +2 -1
- package/openxiangda-skills/references/openxiangda-api.md +27 -0
- package/openxiangda-skills/references/pages/page-sdk.md +11 -1
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +12 -2
- package/package.json +1 -1
- package/packages/sdk/dist/runtime/index.cjs +67 -1
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +1 -1
- package/packages/sdk/dist/runtime/index.d.ts +1 -1
- package/packages/sdk/dist/runtime/index.mjs +67 -1
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/react.cjs +67 -1
- package/packages/sdk/dist/runtime/react.cjs.map +1 -1
- package/packages/sdk/dist/runtime/react.d.mts +13 -1
- package/packages/sdk/dist/runtime/react.d.ts +13 -1
- package/packages/sdk/dist/runtime/react.mjs +67 -1
- package/packages/sdk/dist/runtime/react.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -439,7 +439,7 @@ await ctx.organization.accounts.resetPassword("user-alice", {
|
|
|
439
439
|
})
|
|
440
440
|
```
|
|
441
441
|
|
|
442
|
-
应用登录能力通过 auth resource 和 runtime SDK 提供:登录配置放在 `src/resources/auth/<code>.json`,默认 React SPA 模板已包含 `/view/:appType/login`,自定义页面可使用 `createAuthClient({ appType, servicePrefix })` 或 `LoginPage` / `useAuth` from `openxiangda/runtime/react
|
|
442
|
+
应用登录能力通过 auth resource 和 runtime SDK 提供:登录配置放在 `src/resources/auth/<code>.json`,默认 React SPA 模板已包含 `/view/:appType/login`,自定义页面可使用 `createAuthClient({ appType, servicePrefix })` 或 `LoginPage` / `useAuth` from `openxiangda/runtime/react`。钉钉登录默认使用 `dingtalkFlow="auto"`:只有明确位于钉钉容器且 JSAPI 可用时才走免登码,普通浏览器会请求应用级 OAuth 地址并跳转钉钉认证页;自定义页可调用 `getDingTalkOAuthUrl({ returnUrl })` 接入相同能力。手机号验证码、CAS/SSO 或其他外部登录可以由 App Function provider 校验外部凭证,但 provider 只能返回 `phone` / `email` / `externalId` / `unionId` 等身份声明;平台后端按 auth resource 策略执行账号匹配、绑定、创建或拒绝,并由平台统一签发 token/cookie。默认注册策略是拒绝,开启自动注册或白名单注册前必须确认身份匹配键、默认角色、验证码 TTL/频率/失败次数、审计字段和错误文案策略。
|
|
443
443
|
|
|
444
444
|
常用数据视图命令:
|
|
445
445
|
|
package/lib/cli.js
CHANGED
|
@@ -3568,8 +3568,15 @@ async function authConfig(args) {
|
|
|
3568
3568
|
const result = {
|
|
3569
3569
|
methods: [
|
|
3570
3570
|
{ type: 'password', requiredFields: ['username', 'password'] },
|
|
3571
|
+
{
|
|
3572
|
+
type: 'dingtalk',
|
|
3573
|
+
requiredFields: [],
|
|
3574
|
+
defaultFlow: 'auto',
|
|
3575
|
+
supportedFlows: ['auto', 'jsapi', 'oauth'],
|
|
3576
|
+
},
|
|
3571
3577
|
{ type: 'phone_code', requiredFields: ['phone', 'code'], provider: 'functionCode 或 connector' },
|
|
3572
3578
|
{ type: 'sso', requiredFields: ['provider', 'callbackUrl'] },
|
|
3579
|
+
{ type: 'guest', requiredFields: [] },
|
|
3573
3580
|
],
|
|
3574
3581
|
defaultRegistration: { mode: 'reject' },
|
|
3575
3582
|
defaultBinding: { mode: 'auto' },
|
|
@@ -29,7 +29,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
|
|
|
29
29
|
| 审批流程 / workflow / 流程节点 / JS_CODE | `openxiangda-workflow-automation` | `openxiangda workflow validate / create / publish` |
|
|
30
30
|
| 自动化 / 定时任务 / 提交触发 / cron | `openxiangda-workflow-automation` | `openxiangda automation validate / create / publish / enable` |
|
|
31
31
|
| App Function / function_call / 可复用后端逻辑 | `openxiangda-workflow-automation` | declare `src/resources/functions/<code>.json` + `src/functions/<code>/index.ts` |
|
|
32
|
-
| 应用登录 / Auth SDK / 手机号验证码 / CAS /
|
|
32
|
+
| 应用登录 / Auth SDK / 手机号验证码 / CAS / 钉钉登录或免登 | `openxiangda-architecture-design` + `openxiangda-page` | design security gate first, then declare `src/resources/auth/<code>.json` and use `createAuthClient` / `LoginPage` |
|
|
33
33
|
| 账号权限 / 角色 / 权限组 / 字段权限 / 数据范围 / RBAC | `openxiangda-permission-settings` | `openxiangda design gates --topic permissions --json` → choose permission mode → `openxiangda permission ...` / `openxiangda settings ...` |
|
|
34
34
|
| 平台部门 / 平台账号 / 重置密码 / 组织账号管理 | `openxiangda-architecture-design` + `openxiangda-page` | check `openxiangda organization capabilities --json`; use `sdk.organization` / `ctx.organization` only after `app:organization:manage` is granted |
|
|
35
35
|
| 外部人员无需登录访问 / 公开报名 / 公开查询 / public page | `openxiangda-architecture-design` + `openxiangda-permission-settings` + `openxiangda-page` | 先确认公开范围、外部角色、ticket、grants;再声明 `routes` + `public-access`,并用 `OpenXiangdaProvider` + `OpenXiangdaPageProvider` + `PublicAccessGate` |
|
|
@@ -173,6 +173,7 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
|
|
|
173
173
|
- When a role such as 校区管理员 will create app roles, assign role members, grant role permissions, maintain permission groups, or manage organization accounts, its role manifest must declare the needed `apiPermissionCodes` such as `app:role:manage`, `app:page-permission-group:manage`, `app:form-permission-group:manage`, and `app:organization:manage`. If that administrator creates another administrator role, the new role must also declare its own `apiPermissionCodes`; permissions are not inherited from the creator.
|
|
174
174
|
- If `resource publish` reports a missing API permission point such as `app:role:manage`, treat it as a platform seed/data problem. The platform tenant must have the permission code in `api_permissions`; do not remove the role manifest permission just to make publish pass.
|
|
175
175
|
- For application login, declare auth resources in `src/resources/auth/<code>.json` and publish them with `openxiangda resource publish`. App Function auth providers may validate external credentials and return only an identity assertion; they must never issue tokens, set cookies, or write platform user/binding tables directly. The platform auth service decides create/bind/reject and issues tokens.
|
|
176
|
+
- For DingTalk application login, prefer `flow: "auto"`: `LoginPage` uses JSAPI only inside a confirmed DingTalk container and otherwise starts platform-managed browser OAuth. Custom login pages call `getDingTalkOAuthUrl({ returnUrl })`; they must not assemble DingTalk OAuth URLs, manage callback state, or embed tenant secrets themselves.
|
|
176
177
|
- For external/no-login pages in React SPA apps, declare `src/resources/routes/<code>.json` and `src/resources/public-access/<code>.json`, put the page under `/view/:appType/public/*`, and use `PublicAccessGate` or `createPublicAccessClient`. The route tree must also include `OpenXiangdaPageProvider` inside `OpenXiangdaProvider` before any `usePageSdk()` / `usePageContext()` / `useDataSource()` call; otherwise pages throw `usePageSdkStore 必须在 PageProvider 内使用`. Always provide `fallback` and `errorFallback` for public routes so slow networks, missing tickets, or expired tickets do not render blank pages. Public guest access to forms, dataViews, functions, and connectors is denied unless policy `grants` explicitly names the resource; backend permission groups still apply.
|
|
177
178
|
- When verifying public access, parse the response body and reject string business errors such as `PUBLIC_GRANT_DENIED` even if the HTTP status is 200. Do not use `response.ok` alone as the success condition.
|
|
178
179
|
- Before scaffolding a real app, complex page, data management page, portal shell, status lifecycle, role governance, or automation, read `references/best-practices.md` and pick the architecture first. Prefer copying the relevant pattern from `examples/best-practices/` into `src/` instead of generating a single large page file.
|
|
@@ -186,7 +186,7 @@ Default: reusable calculations and validations become App Functions; one-off bac
|
|
|
186
186
|
|
|
187
187
|
Ask these before generating any login/auth design:
|
|
188
188
|
|
|
189
|
-
- Which methods are enabled: password, DingTalk in-app free login, CAS/SSO, phone code, guest?
|
|
189
|
+
- Which methods are enabled: password, DingTalk browser OAuth/in-app free login, CAS/SSO, phone code, guest?
|
|
190
190
|
- What is the phone registration policy: reject, auto-create, bind existing only, whitelist, or manual approval?
|
|
191
191
|
- What are the identity match keys and priorities: `phone`, `email`, `externalId`, `unionId`, `jobNumber`, `username`?
|
|
192
192
|
- Which App Function provider validates each external credential, and what identity assertion fields must it return?
|
|
@@ -280,6 +280,7 @@ For simple CRUD/admin lists, design can proceed with the appropriate OpenXiangda
|
|
|
280
280
|
- Auth resources use stable local codes under `src/resources/auth/`.
|
|
281
281
|
- Use `/view/:appType/login` or `LoginPage` from `openxiangda/runtime/react` for default React login.
|
|
282
282
|
- Use `createAuthClient({ appType, servicePrefix })` for custom React login pages.
|
|
283
|
+
- DingTalk `flow: "auto"` uses JSAPI only in a confirmed DingTalk container and otherwise starts platform-managed browser OAuth. The platform owns callback state and secrets; app code supplies only an app-local `returnUrl` through `getDingTalkOAuthUrl`.
|
|
283
284
|
- Phone-code providers are App Functions. They validate send/verify events and return identity assertions; they do not issue tokens or mutate platform users.
|
|
284
285
|
- New-user registration must be explicit, with default roles and identity conflict behavior documented.
|
|
285
286
|
|
|
@@ -78,6 +78,33 @@ Body:
|
|
|
78
78
|
|
|
79
79
|
Requires Bearer token. Revokes the current CLI token session.
|
|
80
80
|
|
|
81
|
+
## App Runtime Auth
|
|
82
|
+
|
|
83
|
+
### POST `/apps/:appType/auth/dingtalk/oauth/start`
|
|
84
|
+
|
|
85
|
+
Starts platform-managed DingTalk browser OAuth for an application. This endpoint is called without an existing app login session. The platform creates and stores one-time callback state; application code must not build the DingTalk authorization URL itself.
|
|
86
|
+
|
|
87
|
+
Body:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"returnUrl": "/view/APP_EXAMPLE/admin"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`returnUrl` is optional and, when present, must stay under the current application's `/view/:appType/*` routes.
|
|
96
|
+
|
|
97
|
+
Response data:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"loginUrl": "https://login.dingtalk.com/oauth2/auth?...",
|
|
102
|
+
"expiresIn": 600
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The platform-owned callback consumes the one-time state, creates the authenticated platform session, and redirects to the validated `returnUrl`. React applications normally use `LoginPage dingtalkFlow="auto"`; custom login pages call `createAuthClient(...).getDingTalkOAuthUrl({ returnUrl })` and navigate to `loginUrl`.
|
|
107
|
+
|
|
81
108
|
## App Snapshot
|
|
82
109
|
|
|
83
110
|
### GET `/apps/`
|
|
@@ -247,7 +247,7 @@ Application auth:
|
|
|
247
247
|
import { LoginPage, useAuth, useLoginMethods } from "openxiangda/runtime/react";
|
|
248
248
|
|
|
249
249
|
export function DefaultLogin() {
|
|
250
|
-
return <LoginPage />;
|
|
250
|
+
return <LoginPage dingtalkFlow="auto" />;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
export function CustomPhoneLogin() {
|
|
@@ -269,6 +269,14 @@ import { createAuthClient } from "openxiangda/runtime";
|
|
|
269
269
|
|
|
270
270
|
const auth = createAuthClient({ appType, servicePrefix: "/service" });
|
|
271
271
|
const methods = await auth.getMethods();
|
|
272
|
+
|
|
273
|
+
async function startDingTalkLogin() {
|
|
274
|
+
const { loginUrl } = await auth.getDingTalkOAuthUrl({
|
|
275
|
+
returnUrl: `/view/${encodeURIComponent(appType)}/admin`,
|
|
276
|
+
});
|
|
277
|
+
window.location.assign(loginUrl);
|
|
278
|
+
}
|
|
279
|
+
|
|
272
280
|
const sent = await auth.sendPhoneCode({ phone, purpose: "login" });
|
|
273
281
|
const result = await auth.phoneCodeLogin({
|
|
274
282
|
phone,
|
|
@@ -277,6 +285,8 @@ const result = await auth.phoneCodeLogin({
|
|
|
277
285
|
});
|
|
278
286
|
```
|
|
279
287
|
|
|
288
|
+
`dingtalkFlow="auto"` is the default. It uses DingTalk JSAPI only when both the container and `requestAuthCode` are available; otherwise it starts browser OAuth. Explicit `dingtalkFlow="jsapi"` or `"oauth"` overrides the auth method's `flow` setting. Browser OAuth is a full-page redirect whose callback is handled by the platform, so custom pages should pass an app-local `/view/:appType/*` return URL and must not implement their own callback or OAuth `state`. `LoginPage` normalizes a same-origin absolute guard callback to that relative form and rejects cross-origin or other-app callbacks before making the OAuth start request.
|
|
289
|
+
|
|
280
290
|
For phone-code auth, the App Function provider receives `event`, `appType`, `method`, `credential`, `requestId`, `request`, and `challenge`. It may return `{ ok, providerState }` for send and `{ ok, identity }` for verify. It must not return `token`, `accessToken`, `refreshToken`, cookies, or mutate platform account tables.
|
|
281
291
|
|
|
282
292
|
Public access route:
|
|
@@ -74,7 +74,7 @@ openxiangda permission role-update external_visitor --json-file src/resources/ro
|
|
|
74
74
|
"configJson": {
|
|
75
75
|
"methods": [
|
|
76
76
|
{ "type": "password", "enabled": true, "label": "账号密码" },
|
|
77
|
-
{ "type": "dingtalk", "enabled": true, "label": "
|
|
77
|
+
{ "type": "dingtalk", "enabled": true, "label": "钉钉登录", "flow": "auto" },
|
|
78
78
|
{ "type": "sso", "enabled": true, "label": "CAS", "protocol": "cas" },
|
|
79
79
|
{
|
|
80
80
|
"type": "phone_code",
|
|
@@ -127,7 +127,7 @@ React 默认页:
|
|
|
127
127
|
import { LoginPage } from "openxiangda/runtime/react";
|
|
128
128
|
|
|
129
129
|
export default function AppLogin() {
|
|
130
|
-
return <LoginPage />;
|
|
130
|
+
return <LoginPage dingtalkFlow="auto" />;
|
|
131
131
|
}
|
|
132
132
|
```
|
|
133
133
|
|
|
@@ -138,10 +138,20 @@ import { createAuthClient } from "openxiangda/runtime";
|
|
|
138
138
|
|
|
139
139
|
const auth = createAuthClient({ appType, servicePrefix: "/service" });
|
|
140
140
|
const methods = await auth.getMethods();
|
|
141
|
+
|
|
142
|
+
async function startDingTalkLogin() {
|
|
143
|
+
const { loginUrl } = await auth.getDingTalkOAuthUrl({
|
|
144
|
+
returnUrl: `/view/${encodeURIComponent(appType)}/admin`,
|
|
145
|
+
});
|
|
146
|
+
window.location.assign(loginUrl);
|
|
147
|
+
}
|
|
148
|
+
|
|
141
149
|
const sent = await auth.sendPhoneCode({ phone, purpose: "login" });
|
|
142
150
|
await auth.phoneCodeLogin({ phone, code, challengeId: sent.challengeId });
|
|
143
151
|
```
|
|
144
152
|
|
|
153
|
+
钉钉 `flow: "auto"` 会在确认处于钉钉容器且 JSAPI 可用时走免登,否则走平台托管的浏览器 OAuth。`returnUrl` 只能是当前应用的 `/view/:appType/*` 路径;应用不要自行拼装钉钉授权 URL、保存 OAuth `state` 或实现回调页。
|
|
154
|
+
|
|
145
155
|
设计前必须确认启用方式、注册策略、身份匹配键、provider 边界、默认权限、安全参数、第三方配置归属。
|
|
146
156
|
|
|
147
157
|
## 1. Storage — `src/resources/storage/<code>.json`
|
package/package.json
CHANGED
|
@@ -2284,6 +2284,10 @@ var createAuthClient = ({
|
|
|
2284
2284
|
getMethods: () => request(appAuthPath("/methods")),
|
|
2285
2285
|
passwordLogin: (input) => request(appAuthPath("/password/login"), postJson(input)),
|
|
2286
2286
|
dingtalkLogin: (input) => request(appAuthPath("/dingtalk/login"), postJson(input)),
|
|
2287
|
+
getDingTalkOAuthUrl: (input) => request(
|
|
2288
|
+
appAuthPath("/dingtalk/oauth/start"),
|
|
2289
|
+
postJson(input || {})
|
|
2290
|
+
),
|
|
2287
2291
|
guestLogin: (input) => request(appAuthPath("/guest/login"), postJson(input || {})),
|
|
2288
2292
|
sendPhoneCode: (input) => request(appAuthPath("/phone-code/send"), postJson(input)),
|
|
2289
2293
|
phoneCodeLogin: (input) => request(appAuthPath("/phone-code/login"), postJson(input)),
|
|
@@ -8274,6 +8278,7 @@ var useAuth = (options = {}) => {
|
|
|
8274
8278
|
getMethods: client.getMethods,
|
|
8275
8279
|
passwordLogin: client.passwordLogin,
|
|
8276
8280
|
dingtalkLogin: client.dingtalkLogin,
|
|
8281
|
+
getDingTalkOAuthUrl: client.getDingTalkOAuthUrl,
|
|
8277
8282
|
guestLogin: client.guestLogin,
|
|
8278
8283
|
sendPhoneCode: client.sendPhoneCode,
|
|
8279
8284
|
phoneCodeLogin: client.phoneCodeLogin,
|
|
@@ -8340,6 +8345,7 @@ var LoginPage = ({
|
|
|
8340
8345
|
className,
|
|
8341
8346
|
style,
|
|
8342
8347
|
defaultMethod,
|
|
8348
|
+
dingtalkFlow,
|
|
8343
8349
|
redirectUrl,
|
|
8344
8350
|
redirectOnSuccess = true,
|
|
8345
8351
|
onSuccess,
|
|
@@ -8497,6 +8503,21 @@ var LoginPage = ({
|
|
|
8497
8503
|
setSubmitting(true);
|
|
8498
8504
|
setError(null);
|
|
8499
8505
|
try {
|
|
8506
|
+
const flow = resolveDingTalkLoginFlow(dingtalkFlow, dingtalkMethod);
|
|
8507
|
+
if (flow === "oauth") {
|
|
8508
|
+
const returnUrl = resolveDingTalkOAuthReturnUrl(
|
|
8509
|
+
auth.client.appType,
|
|
8510
|
+
redirectUrl || getCallbackUrl() || void 0
|
|
8511
|
+
);
|
|
8512
|
+
const result = await auth.getDingTalkOAuthUrl({
|
|
8513
|
+
returnUrl
|
|
8514
|
+
});
|
|
8515
|
+
if (typeof window === "undefined") {
|
|
8516
|
+
throw new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u8DF3\u8F6C\u9489\u9489\u767B\u5F55");
|
|
8517
|
+
}
|
|
8518
|
+
window.location.assign(result.loginUrl);
|
|
8519
|
+
return;
|
|
8520
|
+
}
|
|
8500
8521
|
const code = await requestDingTalkCode(dingtalkMethod);
|
|
8501
8522
|
await handleSuccess(
|
|
8502
8523
|
await auth.dingtalkLogin({
|
|
@@ -8613,7 +8634,7 @@ var LoginPage = ({
|
|
|
8613
8634
|
icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons10.QrcodeOutlined, {}),
|
|
8614
8635
|
loading: submitting,
|
|
8615
8636
|
onClick: handleDingTalkLogin,
|
|
8616
|
-
children: dingtalkMethod.label || "\u9489\u9489\
|
|
8637
|
+
children: dingtalkMethod.label || "\u9489\u9489\u767B\u5F55"
|
|
8617
8638
|
}
|
|
8618
8639
|
) : null,
|
|
8619
8640
|
ssoMethod ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
@@ -8764,6 +8785,50 @@ var getString = (value, key) => {
|
|
|
8764
8785
|
const result = value[key];
|
|
8765
8786
|
return typeof result === "string" ? result : void 0;
|
|
8766
8787
|
};
|
|
8788
|
+
var resolveDingTalkLoginFlow = (explicitFlow, method) => {
|
|
8789
|
+
const configuredFlow = normalizeDingTalkLoginFlow(getString(method, "flow"));
|
|
8790
|
+
const flow = explicitFlow || configuredFlow || "auto";
|
|
8791
|
+
if (flow !== "auto") return flow;
|
|
8792
|
+
return canUseDingTalkJsApi() ? "jsapi" : "oauth";
|
|
8793
|
+
};
|
|
8794
|
+
var resolveDingTalkOAuthReturnUrl = (appType, returnUrl, origin = getCurrentOrigin()) => {
|
|
8795
|
+
const normalizedAppType = String(appType || "").trim();
|
|
8796
|
+
if (!normalizedAppType) throw new Error("appType \u4E0D\u80FD\u4E3A\u7A7A");
|
|
8797
|
+
const appRoot = `/view/${encodeURIComponent(normalizedAppType)}`;
|
|
8798
|
+
const rawReturnUrl = String(returnUrl || "").trim();
|
|
8799
|
+
if (!rawReturnUrl) return appRoot;
|
|
8800
|
+
if (!origin || rawReturnUrl.startsWith("//")) {
|
|
8801
|
+
throw createInvalidDingTalkReturnUrlError(appRoot);
|
|
8802
|
+
}
|
|
8803
|
+
let baseUrl;
|
|
8804
|
+
let targetUrl;
|
|
8805
|
+
try {
|
|
8806
|
+
baseUrl = new URL(origin);
|
|
8807
|
+
targetUrl = new URL(rawReturnUrl, baseUrl);
|
|
8808
|
+
} catch {
|
|
8809
|
+
throw createInvalidDingTalkReturnUrlError(appRoot);
|
|
8810
|
+
}
|
|
8811
|
+
if (targetUrl.origin !== baseUrl.origin || targetUrl.username || targetUrl.password || targetUrl.pathname !== appRoot && !targetUrl.pathname.startsWith(`${appRoot}/`)) {
|
|
8812
|
+
throw createInvalidDingTalkReturnUrlError(appRoot);
|
|
8813
|
+
}
|
|
8814
|
+
return `${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
|
|
8815
|
+
};
|
|
8816
|
+
var createInvalidDingTalkReturnUrlError = (appRoot) => new Error(`\u9489\u9489\u767B\u5F55\u8FD4\u56DE\u5730\u5740\u5FC5\u987B\u4F4D\u4E8E\u5F53\u524D\u5E94\u7528 ${appRoot} \u4E0B`);
|
|
8817
|
+
var normalizeDingTalkLoginFlow = (value) => value === "auto" || value === "jsapi" || value === "oauth" ? value : void 0;
|
|
8818
|
+
var canUseDingTalkJsApi = () => {
|
|
8819
|
+
if (typeof window === "undefined") return false;
|
|
8820
|
+
const dd = window.dd;
|
|
8821
|
+
const requestAuthCode = dd?.runtime?.permission?.requestAuthCode || dd?.requestAuthCode;
|
|
8822
|
+
if (typeof requestAuthCode !== "function") return false;
|
|
8823
|
+
const platform = String(dd?.env?.platform || "").trim().toLowerCase();
|
|
8824
|
+
if (platform === "notindingtalk") return false;
|
|
8825
|
+
if (["android", "iphone", "ipad", "ios", "pc", "mac", "windows", "win"].includes(
|
|
8826
|
+
platform
|
|
8827
|
+
)) {
|
|
8828
|
+
return true;
|
|
8829
|
+
}
|
|
8830
|
+
return /dingtalk/i.test(window.navigator?.userAgent || "");
|
|
8831
|
+
};
|
|
8767
8832
|
var requestDingTalkCode = (method) => {
|
|
8768
8833
|
const dd = typeof window === "undefined" ? void 0 : window.dd;
|
|
8769
8834
|
const corpId = getString(method, "corpId");
|
|
@@ -8808,6 +8873,7 @@ var readChallengeId = (challenge) => {
|
|
|
8808
8873
|
};
|
|
8809
8874
|
var readChallengeQuestion = (challenge) => typeof challenge.question === "string" ? challenge.question : void 0;
|
|
8810
8875
|
var getCurrentHref3 = () => typeof window === "undefined" ? "" : window.location.href;
|
|
8876
|
+
var getCurrentOrigin = () => typeof window === "undefined" ? "" : window.location.origin;
|
|
8811
8877
|
var getCurrentHostname = () => typeof window === "undefined" ? "" : window.location.hostname;
|
|
8812
8878
|
var getCallbackUrl = () => {
|
|
8813
8879
|
if (typeof window === "undefined") return "";
|