openxiangda 1.0.86 → 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.
Files changed (31) hide show
  1. package/README.md +30 -0
  2. package/lib/cli.js +391 -0
  3. package/openxiangda-skills/SKILL.md +5 -1
  4. package/openxiangda-skills/references/architecture-design.md +29 -0
  5. package/openxiangda-skills/references/openxiangda-api.md +109 -3
  6. package/openxiangda-skills/references/pages/page-sdk.md +35 -0
  7. package/openxiangda-skills/references/permissions-settings.md +39 -2
  8. package/openxiangda-skills/references/resource-manifest-cheatsheet.md +72 -4
  9. package/package.json +1 -1
  10. package/packages/sdk/dist/runtime/index.cjs +3624 -3394
  11. package/packages/sdk/dist/runtime/index.cjs.map +1 -1
  12. package/packages/sdk/dist/runtime/index.d.mts +4 -1001
  13. package/packages/sdk/dist/runtime/index.d.ts +4 -1001
  14. package/packages/sdk/dist/runtime/index.mjs +3083 -2855
  15. package/packages/sdk/dist/runtime/index.mjs.map +1 -1
  16. package/packages/sdk/dist/runtime/react.cjs +2826 -121
  17. package/packages/sdk/dist/runtime/react.cjs.map +1 -1
  18. package/packages/sdk/dist/runtime/react.d.mts +1400 -2
  19. package/packages/sdk/dist/runtime/react.d.ts +1400 -2
  20. package/packages/sdk/dist/runtime/react.mjs +2782 -89
  21. package/packages/sdk/dist/runtime/react.mjs.map +1 -1
  22. package/templates/openxiangda-react-spa/AGENTS.md +29 -0
  23. package/templates/openxiangda-react-spa/src/app/router.tsx +21 -1
  24. package/templates/openxiangda-react-spa/src/pages/public/PublicRegisterPage.tsx +15 -0
  25. package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/public-visitor.json +8 -0
  26. package/templates/openxiangda-react-spa/src/resources/public-access/public-register.json +14 -0
  27. package/templates/openxiangda-react-spa/src/resources/routes/public-register.json +8 -0
  28. package/templates/openxiangda-react-spa/tsconfig.app.json +1 -1
  29. package/templates/openxiangda-react-spa/vite.config.ts +1 -1
  30. package/packages/sdk/dist/openxiangdaProvider-CaXMpsnK.d.mts +0 -328
  31. package/packages/sdk/dist/openxiangdaProvider-CaXMpsnK.d.ts +0 -328
@@ -166,11 +166,11 @@ Body:
166
166
 
167
167
  ### GET `/apps/:appType/forms/:formUuid/public-access`
168
168
 
169
- Requires Bearer token. Returns public/guest access config for the form.
169
+ Requires Bearer token. Returns legacy public/guest access config for the form. This endpoint is only for old `sy-lowcode-view` compatibility.
170
170
 
171
171
  ### PUT `/apps/:appType/forms/:formUuid/public-access`
172
172
 
173
- Requires Bearer token. Creates or updates public/guest access config.
173
+ Requires Bearer token. Creates or updates legacy public/guest access config.
174
174
 
175
175
  Body:
176
176
 
@@ -183,7 +183,113 @@ Body:
183
183
 
184
184
  ### DELETE `/apps/:appType/forms/:formUuid/public-access`
185
185
 
186
- Requires Bearer token. Deletes public/guest access config for the form.
186
+ Requires Bearer token. Deletes legacy public/guest access config for the form.
187
+
188
+ ## React SPA Public Access
189
+
190
+ New React SPA apps use `/view/:appType/public/*`, route resources, public access policies, and a scoped public session. Do not use `?publicAccess=guest` for new apps.
191
+
192
+ ### GET `/apps/:appType/routes`
193
+
194
+ Requires Bearer token. Lists route resources.
195
+
196
+ ### POST `/apps/:appType/routes`
197
+
198
+ Requires Bearer token. Creates a route resource.
199
+
200
+ Body:
201
+
202
+ ```json
203
+ {
204
+ "code": "public.register",
205
+ "title": "公开报名",
206
+ "kind": "page",
207
+ "pathPattern": "/view/:appType/public/register",
208
+ "publicAccess": "guest",
209
+ "publicPolicyCode": "public_register"
210
+ }
211
+ ```
212
+
213
+ ### PUT `/apps/:appType/routes/:code`
214
+
215
+ Requires Bearer token. Updates a route resource.
216
+
217
+ ### DELETE `/apps/:appType/routes/:code`
218
+
219
+ Requires Bearer token. Deletes a route resource.
220
+
221
+ ### GET `/apps/:appType/public-access/policies`
222
+
223
+ Requires Bearer token. Lists public access policies.
224
+
225
+ ### POST `/apps/:appType/public-access/policies`
226
+
227
+ Requires Bearer token. Creates a public access policy.
228
+
229
+ Body:
230
+
231
+ ```json
232
+ {
233
+ "code": "public_register",
234
+ "name": "公开报名入口",
235
+ "enabled": true,
236
+ "mode": "guest",
237
+ "routeCode": "public.register",
238
+ "pathPattern": "/view/:appType/public/register",
239
+ "externalRoleCodes": ["external_visitor"],
240
+ "grants": {
241
+ "forms": ["FORM_UUID"],
242
+ "dataViews": ["public_registration_lookup"],
243
+ "functions": ["submit_public_registration"],
244
+ "connectors": ["sms.sendCode"]
245
+ }
246
+ }
247
+ ```
248
+
249
+ ### PUT `/apps/:appType/public-access/policies/:code`
250
+
251
+ Requires Bearer token. Updates a public access policy.
252
+
253
+ ### DELETE `/apps/:appType/public-access/policies/:code`
254
+
255
+ Requires Bearer token. Deletes a public access policy.
256
+
257
+ ### POST `/apps/:appType/public-access/policies/:code/tickets`
258
+
259
+ Requires Bearer token. Creates a ticket for a `mode: "ticket"` policy.
260
+
261
+ Body:
262
+
263
+ ```json
264
+ {
265
+ "expiresAt": "2026-06-18T12:00:00.000Z",
266
+ "subject": { "scenario": "score-link" }
267
+ }
268
+ ```
269
+
270
+ Tickets are single-use by default. Set policy `ticketConfig.singleUse: false` only when the link is intentionally reusable.
271
+
272
+ ### POST `/apps/:appType/public/session`
273
+
274
+ Does not require an existing login. Creates a scoped public guest session.
275
+
276
+ Body:
277
+
278
+ ```json
279
+ {
280
+ "policyCode": "public_register",
281
+ "routeCode": "public.register",
282
+ "path": "/view/APP_XXX/public/register",
283
+ "ticket": "optional-ticket",
284
+ "guestIdentifier": "public:APP_XXX:browser-id",
285
+ "domain": "example.com",
286
+ "userAgent": "browser"
287
+ }
288
+ ```
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
+
292
+ Returns the normal guest token payload plus `extra.publicAccess`.
187
293
 
188
294
  ### GET `/apps/:appType/menus`
189
295
 
@@ -15,6 +15,7 @@ Guidelines:
15
15
  - Use `sdk.connector.invoke`, `sdk.connector.call("connector.api")`, or `sdk.connector.download` for external services. The SDK calls the platform runtime connector endpoint; it must not call third-party domains directly.
16
16
  - Use `sdk.notification.sendByType` and `batchSendByType` for reusable business messages. Custom notification types must be declared in `src/resources/notifications/` and published with `openxiangda resource publish`.
17
17
  - Use `createAuthClient` from `openxiangda/runtime` or `LoginPage` / `useAuth` from `openxiangda/runtime/react` for application login pages. Auth provider App Functions return identity assertions only; platform auth owns create/bind/reject/token decisions.
18
+ - Use `PublicAccessGate` from `openxiangda/runtime/react` or `createPublicAccessClient` from `openxiangda/runtime` for React SPA public pages under `/view/:appType/public/*`. Do not append old `?publicAccess=guest` links in new apps.
18
19
  - For the current user's department hierarchy, use `sdk.department.getCurrentUserParentDepartments()`; do not hardcode `GET /department/:id/parentDepartments` in page code.
19
20
  - Use `sdk.auth.logoutAndRedirect({ loginUrl })` for user logout when the page should return after login. It calls the platform logout endpoint, appends the current page URL as `callback`, and redirects to the login URL. Use `sdk.auth.logout()` only when the page wants to handle redirect itself.
20
21
  - Use `sdk.role.getMyRoles()`, `sdk.role.getCurrentRole()`, and `sdk.role.switchAppRole()` for current-user app role switching. Pass `roleId: ""` to switch back to all app roles.
@@ -141,6 +142,40 @@ const result = await auth.phoneCodeLogin({
141
142
 
142
143
  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.
143
144
 
145
+ Public access route:
146
+
147
+ ```tsx
148
+ import { PublicAccessGate } from "openxiangda/runtime/react";
149
+
150
+ export function PublicRegisterRoute() {
151
+ return (
152
+ <PublicAccessGate
153
+ policyCode="public_register"
154
+ routeCode="public.register"
155
+ >
156
+ <PublicRegisterPage />
157
+ </PublicAccessGate>
158
+ );
159
+ }
160
+ ```
161
+
162
+ Standalone public session client:
163
+
164
+ ```ts
165
+ import { createPublicAccessClient } from "openxiangda/runtime";
166
+
167
+ const publicAccess = createPublicAccessClient({ appType, servicePrefix: "/service" });
168
+
169
+ await publicAccess.startSession({
170
+ policyCode: "public_register",
171
+ routeCode: "public.register",
172
+ path: window.location.pathname,
173
+ ticket: new URLSearchParams(window.location.search).get("ticket") || undefined,
174
+ });
175
+ ```
176
+
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
+
144
179
  Logout and current-user role switching:
145
180
 
146
181
  ```ts
@@ -185,7 +185,44 @@ Data management config is stored as an opaque JSON object by the platform. Keep
185
185
  }
186
186
  ```
187
187
 
188
- Public access config:
188
+ ## Public Access
189
+
190
+ 新 React SPA 应用的公开访问使用应用路由和公开策略资源:
191
+
192
+ ```json
193
+ {
194
+ "code": "public.register",
195
+ "pathPattern": "/view/:appType/public/register",
196
+ "publicAccess": "guest",
197
+ "publicPolicyCode": "public_register"
198
+ }
199
+ ```
200
+
201
+ ```json
202
+ {
203
+ "code": "public_register",
204
+ "mode": "guest",
205
+ "routeCode": "public.register",
206
+ "externalRoleCodes": ["external_visitor"],
207
+ "grants": {
208
+ "forms": ["registration_form"],
209
+ "dataViews": ["public_registration_lookup"],
210
+ "functions": ["submit_public_registration"],
211
+ "connectors": ["sms.sendCode"]
212
+ }
213
+ }
214
+ ```
215
+
216
+ Rules:
217
+
218
+ - Public routes live under `/view/:appType/public/*`.
219
+ - Public users get a scoped `publicAccess` claim, not a normal app role assignment.
220
+ - Use virtual external role codes, such as `external_visitor`, in page/form/dataView permission groups.
221
+ - Form/dataView/function/connector access is denied unless the policy explicitly grants it.
222
+ - `mode: "ticket"` requires a valid ticket for sensitive links.
223
+ - Do not use `?publicAccess=guest` for new React SPA apps.
224
+
225
+ Legacy form public access config:
189
226
 
190
227
  ```json
191
228
  {
@@ -194,4 +231,4 @@ Public access config:
194
231
  }
195
232
  ```
196
233
 
197
- Public access is resolved by `appType + formUuid`; no local ID mapping is needed.
234
+ This old form-level setting is resolved by `appType + formUuid` and exists only for old `sy-lowcode-view` compatibility.
@@ -101,7 +101,74 @@ await auth.phoneCodeLogin({ phone, code, challengeId: sent.challengeId });
101
101
 
102
102
  设计前必须确认启用方式、注册策略、身份匹配键、provider 边界、默认权限、安全参数、第三方配置归属。
103
103
 
104
- ## 1. Connector — `src/resources/connectors/<code>.json`
104
+ ## 1. Public Route — `src/resources/routes/<code>.json`
105
+
106
+ 新 React SPA 公开页使用 `/view/:appType/public/*`,不要再使用旧 `?publicAccess=guest`。
107
+
108
+ ```json
109
+ {
110
+ "code": "public.register",
111
+ "title": "公开报名",
112
+ "kind": "page",
113
+ "pathPattern": "/view/:appType/public/register",
114
+ "publicAccess": "guest",
115
+ "publicPolicyCode": "public_register"
116
+ }
117
+ ```
118
+
119
+ React Router 中用 `PublicAccessGate` 创建 scoped public session:
120
+
121
+ ```tsx
122
+ import { PublicAccessGate } from "openxiangda/runtime/react";
123
+
124
+ <PublicAccessGate policyCode="public_register" routeCode="public.register">
125
+ <PublicRegisterPage />
126
+ </PublicAccessGate>
127
+ ```
128
+
129
+ ## 2. Public Access Policy — `src/resources/public-access/<code>.json`
130
+
131
+ 公开策略声明外部角色和可访问资源。未显式 grant 的 form/dataView/function/connector 默认拒绝;grant 后仍受对应后端权限组控制。
132
+
133
+ ```json
134
+ {
135
+ "code": "public_register",
136
+ "name": "公开报名入口",
137
+ "mode": "guest",
138
+ "routeCode": "public.register",
139
+ "pathPattern": "/view/:appType/public/register",
140
+ "externalRoleCodes": ["external_visitor"],
141
+ "grants": {
142
+ "forms": ["registration_form"],
143
+ "dataViews": ["public_registration_lookup"],
144
+ "functions": ["submit_public_registration"],
145
+ "connectors": ["sms.sendCode"]
146
+ }
147
+ }
148
+ ```
149
+
150
+ Ticket 模式:
151
+
152
+ ```json
153
+ {
154
+ "code": "public_score_lookup",
155
+ "name": "公开成绩查询",
156
+ "mode": "ticket",
157
+ "routeCode": "public.scoreLookup",
158
+ "pathPattern": "/view/:appType/public/score",
159
+ "externalRoleCodes": ["external_ticket_holder"],
160
+ "ticketConfig": { "ttlSeconds": 1800, "singleUse": true },
161
+ "grants": {
162
+ "dataViews": ["public_score_lookup"]
163
+ }
164
+ }
165
+ ```
166
+
167
+ Ticket 默认单次使用,首次换取 public session 后立即失效;只有明确配置 `ticketConfig.singleUse: false` 的业务场景才允许复用。
168
+
169
+ `grants.forms` 可以写本地 `formCode`,CLI 发布时会解析为真实 `formUuid`。
170
+
171
+ ## 3. Connector — `src/resources/connectors/<code>.json`
105
172
 
106
173
  ```json
107
174
  {
@@ -140,7 +207,7 @@ const data = await sdk.connector.call("crm.getCustomer", { body: { keyword } });
140
207
 
141
208
  不要把 `authConfig` 里的真实 secret 写进 manifest;用 placeholder,由平台管理员在后台覆盖。完整字段见 [`connector-resources.md`](connector-resources.md)。
142
209
 
143
- ## 2. Data View — `src/resources/data-views/<code>.json`
210
+ ## 4. Data View — `src/resources/data-views/<code>.json`
144
211
 
145
212
  选择规则:
146
213
 
@@ -488,11 +555,12 @@ export default async function (ctx) {
488
555
  { "fields": ["customerCode"], "unique": true },
489
556
  { "fields": ["status", "ownerDept"] }
490
557
  ],
491
- "dataManagement": { "enabled": true, "default": "list" },
492
- "publicAccess": { "enabled": false }
558
+ "dataManagement": { "enabled": true, "default": "list" }
493
559
  }
494
560
  ```
495
561
 
562
+ `publicAccess` 表单 setting 只用于旧 `sy-lowcode-view` 兼容。新 React SPA 公开页面必须使用 `src/resources/routes/` + `src/resources/public-access/` + `PublicAccessGate`。
563
+
496
564
  ## 12. Menu — `src/resources/menus/<code>.json`
497
565
 
498
566
  ```json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.86",
3
+ "version": "1.0.88",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {