openxiangda 1.0.87 → 1.0.88
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 +2 -0
- package/openxiangda-skills/references/openxiangda-api.md +5 -1
- package/openxiangda-skills/references/pages/page-sdk.md +1 -1
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +3 -1
- package/package.json +1 -1
- package/packages/sdk/dist/runtime/index.cjs +37 -9
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.mjs +37 -9
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/react.cjs +37 -9
- package/packages/sdk/dist/runtime/react.cjs.map +1 -1
- package/packages/sdk/dist/runtime/react.d.mts +9 -3
- package/packages/sdk/dist/runtime/react.d.ts +9 -3
- package/packages/sdk/dist/runtime/react.mjs +37 -9
- package/packages/sdk/dist/runtime/react.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -176,6 +176,8 @@ const affiliatedDepartmentExternalId = user?.affiliatedDepartment?.externalId
|
|
|
176
176
|
|
|
177
177
|
React SPA 新应用的无需登录访问统一使用 `/view/:appType/public/*`。应用在 `src/resources/routes/*.json` 声明公开路由,在 `src/resources/public-access/*.json` 声明公开策略、外部角色和可访问资源 grant,页面用 `PublicAccessGate` 或 `createPublicAccessClient` 创建 scoped public session。公开 guest 的 form、dataView、function、connector 默认全部拒绝,只有 policy `grants` 明确列出的资源可访问,并且仍受对应表单权限组、dataView 权限组等后端权限控制。
|
|
178
178
|
|
|
179
|
+
`mode: "ticket"` 的公开策略默认按单次 ticket 使用;只有明确配置 `ticketConfig.singleUse: false` 时才允许复用。新 public session 只返回 bearer token,SDK 会把 token 注入后续 runtime/bootstrap、dataView、function、connector 请求,不依赖认证 cookie。
|
|
180
|
+
|
|
179
181
|
旧 `?publicAccess=guest` 和表单 `settings/forms/*.json` 里的 `publicAccess` 只用于旧 `sy-lowcode-view` 兼容。新 React SPA 应用不要再设计或生成这种链接。
|
|
180
182
|
|
|
181
183
|
```json
|
|
@@ -263,10 +263,12 @@ Body:
|
|
|
263
263
|
```json
|
|
264
264
|
{
|
|
265
265
|
"expiresAt": "2026-06-18T12:00:00.000Z",
|
|
266
|
-
"subject": { "
|
|
266
|
+
"subject": { "scenario": "score-link" }
|
|
267
267
|
}
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
Tickets are single-use by default. Set policy `ticketConfig.singleUse: false` only when the link is intentionally reusable.
|
|
271
|
+
|
|
270
272
|
### POST `/apps/:appType/public/session`
|
|
271
273
|
|
|
272
274
|
Does not require an existing login. Creates a scoped public guest session.
|
|
@@ -285,6 +287,8 @@ Body:
|
|
|
285
287
|
}
|
|
286
288
|
```
|
|
287
289
|
|
|
290
|
+
The response returns a scoped bearer token. New React SPA apps must use `PublicAccessGate` or `createPublicAccessClient` so follow-up runtime/bootstrap, dataView, function, and connector calls include `Authorization: Bearer <token>`. Do not depend on auth cookies for public sessions.
|
|
291
|
+
|
|
288
292
|
Returns the normal guest token payload plus `extra.publicAccess`.
|
|
289
293
|
|
|
290
294
|
### GET `/apps/:appType/menus`
|
|
@@ -174,7 +174,7 @@ await publicAccess.startSession({
|
|
|
174
174
|
});
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
-
The matching resources must exist under `src/resources/routes/` and `src/resources/public-access/`. Public guest access to forms, data views, functions, and connectors is denied unless the policy `grants` explicitly names that resource.
|
|
177
|
+
`PublicAccessGate` stores the returned bearer token in the runtime provider and injects it into follow-up SDK requests. If you call `createPublicAccessClient` directly outside the provider, pass the returned `accessToken` as `Authorization: Bearer <token>` for follow-up APIs. The matching resources must exist under `src/resources/routes/` and `src/resources/public-access/`. Public guest access to forms, data views, functions, and connectors is denied unless the policy `grants` explicitly names that resource.
|
|
178
178
|
|
|
179
179
|
Logout and current-user role switching:
|
|
180
180
|
|
|
@@ -157,13 +157,15 @@ Ticket 模式:
|
|
|
157
157
|
"routeCode": "public.scoreLookup",
|
|
158
158
|
"pathPattern": "/view/:appType/public/score",
|
|
159
159
|
"externalRoleCodes": ["external_ticket_holder"],
|
|
160
|
-
"ticketConfig": { "ttlSeconds": 1800 },
|
|
160
|
+
"ticketConfig": { "ttlSeconds": 1800, "singleUse": true },
|
|
161
161
|
"grants": {
|
|
162
162
|
"dataViews": ["public_score_lookup"]
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
+
Ticket 默认单次使用,首次换取 public session 后立即失效;只有明确配置 `ticketConfig.singleUse: false` 的业务场景才允许复用。
|
|
168
|
+
|
|
167
169
|
`grants.forms` 可以写本地 `formCode`,CLI 发布时会解析为真实 `formUuid`。
|
|
168
170
|
|
|
169
171
|
## 3. Connector — `src/resources/connectors/<code>.json`
|
package/package.json
CHANGED
|
@@ -4102,12 +4102,23 @@ var OpenXiangdaProvider = ({
|
|
|
4102
4102
|
() => appType || resolveAppTypeFromLocation(),
|
|
4103
4103
|
[appType]
|
|
4104
4104
|
);
|
|
4105
|
+
const [accessToken, setAccessTokenState] = (0, import_react8.useState)(null);
|
|
4106
|
+
const setAccessToken = (0, import_react8.useCallback)(
|
|
4107
|
+
(nextAccessToken) => {
|
|
4108
|
+
setAccessTokenState(nextAccessToken || null);
|
|
4109
|
+
},
|
|
4110
|
+
[]
|
|
4111
|
+
);
|
|
4112
|
+
const authorizedFetch = (0, import_react8.useMemo)(
|
|
4113
|
+
() => createAuthorizedFetch(resolvedFetch, accessToken),
|
|
4114
|
+
[accessToken, resolvedFetch]
|
|
4115
|
+
);
|
|
4105
4116
|
const [state, setState] = (0, import_react8.useState)({
|
|
4106
4117
|
data: null,
|
|
4107
4118
|
loading: true,
|
|
4108
4119
|
error: null
|
|
4109
4120
|
});
|
|
4110
|
-
const reload = (0, import_react8.useCallback)(async () => {
|
|
4121
|
+
const reload = (0, import_react8.useCallback)(async (options = {}) => {
|
|
4111
4122
|
if (!resolvedAppType) {
|
|
4112
4123
|
setState({
|
|
4113
4124
|
data: null,
|
|
@@ -4120,8 +4131,9 @@ var OpenXiangdaProvider = ({
|
|
|
4120
4131
|
return;
|
|
4121
4132
|
}
|
|
4122
4133
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
4134
|
+
const requestFetch = options.accessToken !== void 0 ? createAuthorizedFetch(resolvedFetch, options.accessToken || null) : authorizedFetch;
|
|
4123
4135
|
try {
|
|
4124
|
-
const response = await
|
|
4136
|
+
const response = await requestFetch(
|
|
4125
4137
|
buildServiceUrl3(
|
|
4126
4138
|
servicePrefix,
|
|
4127
4139
|
`/openxiangda-api/v1/apps/${encodeURIComponent(
|
|
@@ -4153,7 +4165,7 @@ var OpenXiangdaProvider = ({
|
|
|
4153
4165
|
error: normalizeRuntimeError(error)
|
|
4154
4166
|
});
|
|
4155
4167
|
}
|
|
4156
|
-
}, [resolvedAppType, resolvedFetch, servicePrefix]);
|
|
4168
|
+
}, [authorizedFetch, resolvedAppType, resolvedFetch, servicePrefix]);
|
|
4157
4169
|
(0, import_react8.useEffect)(() => {
|
|
4158
4170
|
void reload();
|
|
4159
4171
|
}, [reload]);
|
|
@@ -4162,10 +4174,11 @@ var OpenXiangdaProvider = ({
|
|
|
4162
4174
|
...state,
|
|
4163
4175
|
appType: resolvedAppType,
|
|
4164
4176
|
servicePrefix,
|
|
4165
|
-
fetchImpl:
|
|
4166
|
-
reload
|
|
4177
|
+
fetchImpl: authorizedFetch,
|
|
4178
|
+
reload,
|
|
4179
|
+
setAccessToken
|
|
4167
4180
|
}),
|
|
4168
|
-
[reload, resolvedAppType,
|
|
4181
|
+
[authorizedFetch, reload, resolvedAppType, servicePrefix, state]
|
|
4169
4182
|
);
|
|
4170
4183
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OpenXiangdaRuntimeContext.Provider, { value, children });
|
|
4171
4184
|
};
|
|
@@ -4432,6 +4445,19 @@ var buildServiceUrl3 = (servicePrefix, path) => {
|
|
|
4432
4445
|
const suffix = path.startsWith("/") ? path : `/${path}`;
|
|
4433
4446
|
return `${prefix2}${suffix}`;
|
|
4434
4447
|
};
|
|
4448
|
+
var createAuthorizedFetch = (baseFetch, accessToken) => {
|
|
4449
|
+
if (!accessToken) return baseFetch;
|
|
4450
|
+
return ((input, init = {}) => {
|
|
4451
|
+
const headers = new Headers(init.headers || {});
|
|
4452
|
+
if (!headers.has("authorization")) {
|
|
4453
|
+
headers.set("authorization", `Bearer ${accessToken}`);
|
|
4454
|
+
}
|
|
4455
|
+
return baseFetch(input, {
|
|
4456
|
+
...init,
|
|
4457
|
+
headers
|
|
4458
|
+
});
|
|
4459
|
+
});
|
|
4460
|
+
};
|
|
4435
4461
|
var readJsonPayload = async (response) => {
|
|
4436
4462
|
try {
|
|
4437
4463
|
return await response.json();
|
|
@@ -4555,7 +4581,8 @@ var usePublicAccess = (options = {}) => {
|
|
|
4555
4581
|
appType: runtimeAppType,
|
|
4556
4582
|
servicePrefix: runtimeServicePrefix,
|
|
4557
4583
|
fetchImpl: runtimeFetchImpl,
|
|
4558
|
-
reload: reloadRuntime
|
|
4584
|
+
reload: reloadRuntime,
|
|
4585
|
+
setAccessToken
|
|
4559
4586
|
} = runtime;
|
|
4560
4587
|
const {
|
|
4561
4588
|
appType = runtimeAppType,
|
|
@@ -4589,7 +4616,8 @@ var usePublicAccess = (options = {}) => {
|
|
|
4589
4616
|
path: input.path || stableSessionInput.path || readPathFromLocation()
|
|
4590
4617
|
});
|
|
4591
4618
|
setSession(data);
|
|
4592
|
-
|
|
4619
|
+
setAccessToken(data.accessToken);
|
|
4620
|
+
await reloadRuntime({ accessToken: data.accessToken });
|
|
4593
4621
|
setLoading(false);
|
|
4594
4622
|
return data;
|
|
4595
4623
|
} catch (caught) {
|
|
@@ -4602,7 +4630,7 @@ var usePublicAccess = (options = {}) => {
|
|
|
4602
4630
|
throw nextError;
|
|
4603
4631
|
}
|
|
4604
4632
|
},
|
|
4605
|
-
[client, reloadRuntime, stableSessionInput]
|
|
4633
|
+
[client, reloadRuntime, setAccessToken, stableSessionInput]
|
|
4606
4634
|
);
|
|
4607
4635
|
(0, import_react9.useEffect)(() => {
|
|
4608
4636
|
if (!autoStart) return;
|